Doing a database search and send email - php

my first time here and I am quite new to coding.
I have a form that takes the values from a customer table when they want to do a return. This values will then be inserted into a return_product table. However, I need to run another script that does a search in this return product table.
The other script needs to count the total of the transactions in the return_product table group by ID number. When there are customers with 3 or more transactions, they will send an email to the manager. However, the email part should not stop the form from being submitted into the database.
The if loop part is to be done by my friend and she's not done with it yet. What if I need to send out all those who exceed 3 transactions? Do I use a while loop?
I require assistance with making the two scripts run concurrently when the form is being submitted.
Any help is greatly appreciated. Thanks in advance. :)

if you want to count no of records you can use SQL count method to do it!

You can check your condition before inserting values in db and then return respective data like
//Get number of records of particular user with query
//Check the limit
If(num_of_records < 3) {
//Insert data
} else {
//Send mail
}
With this you don't need to write 2 scripts

Related

Php/mysql : How to insert large amount of rows in several tables, in 2 query only

In my app, I have a job that compute something for the user everyday at exactly midnight UTC.
I have a row to insert in table A for each user, for this I first compute a string that I concate in à foreach loop, and then I send the whole string to mysqli_query.
$q = ‘insert into mb_thing_to_compute values’;
foreach($user as $u)
{
$q .= ‘’(NULL, {$u[‘ID’]}, $computedStuff),’’;
}
mysqli_query($q);
This way, It seems there is no overhead time, compared to if I sent the insert one by one
Now the problem is that in a second table, I need to send update notification to user, and each notification row has its params in another table. Only mysql know, after the insert, which ID it inserted the rows so I can’t use the first method because I won’t know what are the inserted notification IDs, needed to insert the notification params (each notif has 3 params).
I thought about giving the notifications IDs a php generated ID, with php uniqId function but there is probably a more « clean » to achieve that ?

mysql - Query to display record just added

I have two pages. One is a form that I use to simply input data that will be sent to my database and the second page that actually takes the data inputted into the form and sends it to the database and is supposed to display the information that I've just added.
Everything works fine, however I'm struggling with the query slightly. What I need it to do is display all the information for the last data inputted to the database.
The query I currently have just displays the data with the highest ID:
$sql = "SELECT * FROM Results ORDER BY ID DESC LIMIT 1";
So as an example I would be left with the following information after completing my form:
Success! Data being saved:
ID = 900 Amount = 206 Date = 2016-12-26
This is obviously just showing the data with the highest ID, but since the ID and all the data fluctuates, I need it to just show the data that has just been inputted.
I came accross this: Query to select newly added records only. But I don't believe this soultion to be viable as the database is external and I don't want to be creating new tables.
I was thinking that it might be possible to assign a hidden value to each newly added record via the query. e.g. New 1, New 2, New 3 etc. Then printing the latest record for New. However, I couldn't find anything on how to do this.
Any help would be greatly appreciated!
You must use this method to have very correct value:
Input form must send to another file that do inserting (we call it here insert.php)
insert.php must insert the data after validation and after that you can fetch the last ID number from database. Depending on the method you are working with it can be different. for example if you are using PDO you can get it by PDO::lastInsertId
after getting the ID you need to forward it to the viewing or editing page. for example view.php?id=LastInsertId. This forward have some reasons:
Codes can be cleaner.
We prevent refresh and resend inserting. for example if you do inserting inside view.php and user hit F5 to refresh the page, The insertion happening again.
This is the whole idea. you can use this method for only one page:
page.php?do=new
page.php?do=insert
forward to the page.php?do=view&id=lastInsertID
why you trying to get just inputted data from database? you can do it using HTTP POST/GET method easily.just send data as parameters and show them in second page.
If you already have the data you are inserting, you don't need to run a query to get it back from the database again, you could just ensure that the query was successful and display the data directly. Anyways:
You can get the insert ID from the last insert using the MySQLi object. For example:
$sql = "<your insert statement>"
$conn->query($sql);
$last_id = $conn->insert_id; //Id of the row you just inserted
$sql = "SELECT * FROM Results WHERE id=$last_id";
This is assuming you do the insert in the same page that you display the result.

Unique Codes - Given to two users who hit script in same second

Hi have a bunch of unique codes in a database which should only be used once.
Two users hit a script which assigns them at the same time and got the same codes!
The script is in Magento and the user can order multiple codes. The issue is if one customer orders 1000 codes the script grabs the top 1000 codes from the DB into an array and then runs through them setting them to "Used" and assigning them to an order. If a second user hits the same script at a similar time the script then grabs the top 1000 codes in the DB at that point in time which crosses over as the first script hasn't had a chance to finish assigning them.
This is unfortunate but has happened quite a few times!
My idea was to create a new table, once the user hits the script a row is made with "order_id" "code_type". Then in the same script a check is done so if a row is in this new table and the "code_type" matches that of which the user is ordering it will wait 60 seconds and check again until the previous codes are issued and the table is empty where it will then create a row and off it goes.
I am not sure if this is the best way or if two users hit at the same second again whether two rows will just be inserted and off we go with the same problem!
Any advice is much appreciated!
The correct answer depends on the database you use.
For example in MySQL with InnoDB the possible solution is a transaction with SELECT ... LOCK IN SHARE MODE.
Schematically it works this by firing following queries:
START TRANSACTION;
SELECT * FROM codes WHERE used = 0 LIMIT 1000 LOCK IN SHARE MODE;
// save ids
UPDATE codes SET used=1 WHERE id IN ( ...ids....);
COMMIT;
More information at http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html

Send confirmation mail to last inserted row

I am trying to create a simple Support Request system which users can insert their email address in a form though jQuery - Ajax and PHP into MySQL database.
After that I need to send a Confirmation Email to the inserted email owner "
every time that a new request inserted into the database". I was thinking about using the Ajax call from database but I am not sure how to select
1- latest inserted row AND
2- Not selected rows to do this( there might be a situation to have two insert at exact same time then the
SELECT email FROM tbl-request ORDER BY id DESC LIMIT 1;
might return Only the last inserted however there where at least two new entries)?
can you please let me know if there is solution to do this through MySQL Trigger or jQuery Ajax
suffii you can add a new colum to the table eg. status which contain 0 as a default value.
Now every time you send a email then update this value to 1.
so you can select the rows for which an email is not sent yet like this..
SELECT email FROM tbl-request where status=0;
It will select only the latest entry containing status = 0.
There can be many way But as my point of view this also can be a better and simplest way
you can do this using cron job.
Run a cron job line every 5 mins and set a flag to check if mail is sent or not. after sending mail set the flag to 1.
We can easily save the last time we checked in a database or file. This method of doing it would allow you to have the emailer system separate from how the record is inserted, which is what I gather you want given that you're suggesting use of Triggers or AJAX to handle it. This method will work even without access to write the database from the PHP script.
At the end of the email script run:
$fh=#fopen('last-email','w');
if (!empty($fh)){
fwrite($fh,time());
fclose($fh);
}
At the start run
$last_email_time=file_get_contents('last-email');
Then add a timestamp field to your table; this will automatically append the time the record was last edited or added.
Then your query will be:
$last_time_as_sql_date=date('Y-m-d H:i:s', $last_email_time);
$query="SELECT email FROM tbl-request WHERE timestamp>'$last_time_as_sql_date' ORDER BY timestamp DESC LIMIT 1;"
How you actually run the script depends more on your implementation; if on a server back end you could run every 5 minutes using crontab -e
*/5 * * * * php /path/to/script.php
You could send the mail from PHP at the moment the request is inserted, but you may want to keep those processes separated.
To do so, an easy fix would be to add a field 'ConfirmationMailed' or something to indicate that that mail was sent. That way you can just query for requests that weren't emailed yet.
A little bit more flexible would be to create a separate table tblRequestCommunication in which you store the communications about the request.
That table could have:
Id (PK), Date, RequestId
Subject
Content
CommunicationType
The communication type could be an enum or a reference to a separate type table in which you store the types of communication to send. One of those types could be 'Automated confirmation message', and in the table you can even store the exact date time, subject and content of that message.
Now, in your query, all you have to do is search for requests without such a confirmation:
SELECT r.email
FROM
tbl-request r
WHERE NOT EXISTS
( SELECT 'x' FROM tblRequestCommunication c
WHERE c.RequestId = r.RequestId
AND c.CommunicationTypeId = 1 /* Automated confirmation */)
This structure will allow you to expand this system for other types as well, for instance an automated mail when the request was closed:
SELECT r.email
FROM
tbl-request r
WHERE
r.State = 'Closed'
AND NOT EXISTS
( SELECT 'x' FROM tblRequestCommunication c
WHERE c.RequestId = r.RequestId
AND c.CommunicationTypeId = 14 /* Close notification */)
Also, you can store 'manual' e-mails and phone reports that are linked to the request in the same table, so you've got a full history of communication.
So, it's a bit of work to create one or two extra tables and change the query, but the abilities of your system will be a lot larger.

Looping through large data array in PHP

I have an array with 100,000 users personal info in (ID, name, email etc). I need to loop through each row of the array and insert a mysql record to a table based on the row data. My problem is that I am running out of memory after about 70,000 rows.
My code:
if(!empty($users)){
$c = 0;
foreach($users as $user){
$message = // Some code to create custom email
queue_mail_to_send($user->user_email, $subject, $message, $db_options, $mail_options, $mail_queue);
}
}
Background:
I am building an email system which sends out an email to the users of my site. The code above is looping through the array of users and executing the function 'queue_mail_to_send' which inserts a mysql row into a email queue table. (I am using a PEAR library to stagger the email sending)
Question:
I know that I am simply exhausting the memory here by trying to do too much in one execution. So does anybody know a better approach to this rather than trying to execute everything in one big loop?
Thanks
I think reducing the payload of the script will be cumbersome and will not give you a satisfying result. If you have any possibility to do so, I would advise you to log which rows you have processed already, and have a script run the next x rows. If you can use a cronjob, you can stage a mail, and let the cronjob add mails to the queue every 5 minutes, until all users are processed.
The easiest way would be to store somewhere, the highest user id you have processed. I would not advise you to store the number of users, because in between batches a user can be added or removed, resulting in users not receiving the e-mail. But if you order by user id (assuming you use an auto-incrementing column for the id!), you can be sure every user gets processed.
So your user query would be something like:
SELECT * FROM users WHERE user_id > [highest_processed_user_id] ORDER BY user_id LIMIT 1000
Then process your loop, and store the last user id:
if(!empty($users)) {
$last_processed_id = null;
foreach($users as $user) {
$message = // Message creation magic
queue_mail_to_send( /** parameters **/ );
$last_processed_id = $user->id;
}
// batch done! store processed user id
$query = 'UPDATE mail_table SET last_processed_user_id = '. $last_processed_id; // please use parameterized statements here
// execute the query
}
And on the next execution, do it again until all users have received the mail.
I have exactly same problem with you. Anyway the answer from #giorgio is the best solutions.
But like java or python, we have "yield" in php. #see [here] (http://php.net/manual/en/language.generators.syntax.php)
Here is my sample code, my case is 50.000 records. and I also test successfully with 370.000 records. But it takes times.
$items = CustomerService::findAll();
foreach ($items AS $item)
{
yield (new self())->loadFromResource($item);
}
You may split that operation in multiple operations, seperated in time.
For instance, only allow your routine to process 40 emails per minute, or maybe use an array of an array, to create "pages" of records (use sql LIMIT function).
And set the arrays of array to null and unset it, when you no longer need that information.
I think you can use MySQL IN clause rather then doing foreach for every user.
Like
user_ids = array (1,2,3,4);
// Do something WHERE user_id IN ($user_ids);
and of sending mails you can user PHPMailer class by supplying comma separated email addresses in $to.
USE just one query like:
INSERT INTO table_name (COL1, Col2,...) SELECT COL1, COL2 FROM other_table;

Categories