Call another php file - php

I'm building an iPhone push server, and trying to get the push to work. I have a message.php file which put new message in the database, and then add the message to a push_queue table in the database.
To send the push, I manually have to go to the browser and call the push file (../push/push.php) which will send out the push.
Is there any way I can call the push.php file from the message.php file automatically?
I tried require_one, include, exec and file_get_contents without any luck.
It works if I use:
header('Location: ../push/push.php');
However, the push.php file takes a couple of seconds to execute and finish, so there's a delay for the user when trying to send a message.
I guess I could use a cron job to call the push.php file, but I'd rather not.
Here is the core function in push.php (based on http://www.raywenderlich.com/3525/apple-push-notification-services-tutorial-part-2):
function start()
{
//writeToLog('Connecting to ' . $this->server);
if (!$this->connectToAPNS())
exit;
while (true)
{
// Do at most 20 messages at a time. Note: we send each message in
// a separate packet to APNS. It would be more efficient if we
// combined several messages into one packet, but this script isn't
// smart enough to do that. ;-)
$stmt = $this->pdo->prepare('SELECT * FROM push_queue WHERE time_sent IS NULL LIMIT 20');
$stmt->execute();
$messages = $stmt->fetchAll(PDO::FETCH_OBJ);
$deletedIds = array();
foreach ($messages as $message)
{
if ($this->sendNotification($message->message_id, $message->device_token, $message->payload))
{
//$stmt = $this->pdo->prepare('UPDATE push_queue SET time_sent = NOW() WHERE message_id = ?');
//$stmt->execute(array($message->message_id));
$deletedIds[] = $message->message_id;
//$stmt = $this->pdo->prepare('DELETE FROM push_queue WHERE message_id = ?');
//$stmt->execute(array($message->message_id));
}
else // failed to deliver
{
$this->reconnectToAPNS();
}
}
//Delete the chunk of messages.
$this->pdo->query('DELETE FROM push_queue WHERE message_id IN ('.implode(',', $deletedIds).')');
unset($messages);
}
}

Create a function or class that does everything that your push.php does and call it when a new message is received or when the iPhone app queries for new messages. In this case you will not need to call other PHP in message.php.
This is a concept of MVC i.e. having your business logic separated from your controllers. In this case pushing is a business logic and message.php and push.php are your controllers.

Related

Using MySQL in multithreaded PHP script ends up to error "MySQL server has gone away"

This question is a little complex so I will first sum up the context :
My app needs to deliver a important amount of push notificaton at a very precise time. FCM (Firebase Cloud Messaging, remote service that delivers the push notification to the devices), has a maximum of 500 push notification per HTTP request.
I couldn't simply loop over pending push notifications in database and send them to FCM without threads , because I would have to wait the response of each request before sending the following.
Therefore, I created a PHP script in the aim of sending N payloads of 500 push notifications to FCM in N http request sent parellely. I used "parallel" PHP librairy, which is the new standard to have PHP with multithreading, as I understood.
The script does that :
// THIS IS THE THREAD CALLBACK :
$sendNotificationBatch = static function(
string $poolId,
int $batchIndex,
array $firebaseCredentialArray,
array $rawFirebaseNotifs)
{
require_once // all necessary libs ...
require_once __DIR__ . "open_sql_co.php" ; // open a new mysql connection here
$factory = (new Factory)->withServiceAccount($firebaseCredentialArray);
$messagingService = $factory->createMessaging();
$firebaseMessages = [];
foreach ($rawFirebaseNotifs as $k => $rawFirebaseNotif)
{
$message = [....] // preparing FCM payload here ..
$firebaseMessages[] = $message ;
}
DebugLog::info("[Pool ID : ".$poolId.", batch $batchIndex] : Sending ".count($firebaseMessages)." notifications..");
$sendReport = $messagingService->sendAll($firebaseMessages);
DebugLog::info("[Pool ID : ".$poolId.", batch $batchIndex] : Sent.");
// **** mark all the notification we've sent as "sent" status in database ****
$fromId = $rawFirebaseNotifs[0]['id'];
$toId = $rawFirebaseNotifs[count($rawFirebaseNotifs) - 1]['id'];
OSQL::set("update pushnotif__queue set sta = 'sent', time_sent = now()
where sending_pool_id = '$poolId' and ID >= $fromId and ID <= $toId");
foreach($sendReport->getItems() as $k => $sendReportItem)
{
// processing report sent back by FCM...
}
};
// MAIN SCRIPT :
while(1)
{
OSQL::set("lock tables pushnotif__queue write");
// poll database continuously
$notifs = OSQL::get("select * from pushnotif__queue where sta = 'pending' order by ID asc");
if($notifs !== false)
{
$poolId = uniqid("", false);
// mark them as 'sending' state and put the poolId
OSQL::set("update pushnotif__queue set
sta = 'sending',
sending_pool_id = '$poolId',
time_inqueue = now()
where sta = 'pending' limit " . MAX_WINDOW_PER_POOL );
// lock and unlock prevent new "pending" notification to be inserted by other part of the server while we set them to "sending" status
OSQL::set("unlock tables");
$pnotifs = [] ;
//now create one thread per group of 500 notifications
$countBatch = ceil(count($pnotifs) / 500) ;
$firebaseRawNotifs = [];
foreach ($pnotifs as $k => $pnotif)
{
$firebaseRawNotifs[] = [
// compute all variable the thread callback will need as primitives values/arrays
//(can't send objects to thread callback)
];
}
DebugLog::info("[Pool ID : ".$poolId."] Pool of " . count($pnotifs) . " notifications found, creating " . $countBatch . " threads.. " );
// create N thread and send them the right part ([0;500], [500-1000], ..) of the full notification array
for($b = 0; $b <= $countBatch - 1; $b++)
{
$len = $b !== $countBatch - 1 ? 500 : $countBatch % 500;
$batch = array_slice($firebaseRawNotifs, $b * 500, $len);
// create the thread and send the payload of push notifs
parallel\run($sendNotificationBatch, [$poolId, $b,$firebaseCredentialArray, $batch] );
}
}
else
{
OSQL::set("unlock tables");
DebugLog::log("no new notification found" );
}
usleep(DELAY_POLL_MS * 1000);
}
Now comes the problem :
Sometime, I have no idea when and why, the MySQL connection gets closed in the thread callback only. For example, the app adds a new pending notification, I have this :
MySQL server has gone away[Pool ID : 5f6525d14bd02] Pool of 1 notifications found, creating 1 threads..
[Pool ID : 5f6525d14bd02, batch 0] : Sending 1 notifications..
[Pool ID : 5f6525d14bd02, batch 0] : Sent.
The push notification is correctly sent, with the right messages and variables so the SQL requests in the main script work well. Though, the SQL request in the thread callback doesn't run. I find my push notifications still in "sending" state.
This problem occurs after a long time. When I first execute the script, everything works well. After several hours, I have the problem.
I saw that MySQL closes TCP connection after 8 hours of inactivity, and it can output this "MySQL server has gone away". But here, a new connection is created in the thread callback, which is created at the time the notification is retrieved from main script. So I don't understand why there would be any "8 hours inactivity" here ..
Thanks for reading
Found myself : I just forgot to close mysql connections at each thread :
mysqli_close($mysqlRes);
As it was only the thread that ended (and not the entiere script), mysql cons weren't closed, eventually accumulating until MySQL decided not to receive any more request.

phpunit testing ???? how shall i compare to xml files before and after api function call(the function contains the stored procedure)

after searching for a long time got this great article its really very nice
but i am facing a bit problem here in my stuff as u have used direct mysql query in api i have used stored procedure in here and every time i have to compare two XML before and after even for a single short and sweet query so is there any alternative for this process but which is this secure
please chk this out u will get i more clearly
database testing in php using phpunit,simpletest on api haveing stored procedure
or how shall i compare to xml files before and after api function call(the function contains the stored procedure)
means i am able to get the before state with mysql-dump but the after but not getting the instant after xml state
sorry for the English but tried my best
thanks for the help friend
have to write an unit test test for the api function
public function delete($userId)
{
// this function calls a stored procedure
$sql = "CALL Delete_User_Details(:userId)";
try {
$db = parent::getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam("userId", $userId);
$stmt->execute();
$id = $stmt->fetchObject();
if ($id == null) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
} else {
$delete_response->createJSONArray("SUCCESS",1);
}
} catch (PDOException $e) {
$delete_response->createJSONArray("DATABASE_ERROR",0);
}
return $delete_response->toJSON();
}
i have writen this unit test for it now want to write an dbunit for it
public function testDeleteUser()
{
$decodedResponse = $response->json();
$this->assertEquals($response->getStatusCode(), 200);
$this->assertEquals($decodedResponse['status']['StatusMSG'], 'SUCCESS');
$this->assertEquals($decodedResponse['status']['Code'], '1');
}
help guyss
u can just simply test it before by calling the query like
$sql = "select * from user";
and compare it with BeforeDeleteUser.xml
And the Call Ur stored procedure
$sql = "CALL Delete_User_Details(:userId)";
And for the after case just repeat the before one again
$sql = "select * from user";
and compare it with AfterDeleteUser.xml
see the logic is very simple if u have 5 Users in BeforeDeleteUser.xml and it results true and after the call of CALL Delete_User_Details(:userId) stored procedure , the AfterDeleteUser.xml should contain only 4 user (or maybe idDelete field to 0 that depends on ur implementation)

Long polling JQUERY chat using sleep()

The following code makes the web loading for like 10 minutes and I dont know why!
function chatheartbeat(){
include("config.php");
$useradn = $_SESSION['displayname'];
$query = "select * from chat where (userbdn = '".$useradn."' AND isread = 1) order by id ASC";
$result = mysql_query($query , $link);
$num_rows = mysql_num_rows($result);
if ($num_rows >= 1) {
$items = array();
$i='1';
while($chat = mysql_fetch_array($result)){
$items[$i]['from']=$chat['useradn'];
$items[$i]['msg']=$chat['msg'];
$items[$i]['timee']=date("H:i" ,$chat['timee']);
$i++;
}
$query = "update chat set isread = 0 where userbdn = '".$useradn."' and isread = 1";
mysql_query($query , $link);
header('Content-type: application/json');
echo json_encode($items);
exit;
}else{
sleep(2);
chatheartbeat();
}
}
Any suggestions?
The function will never return until there are some results from the first select.
I would suggest that you return after n runs through (e.g. 5), even if there are no results. The client can then re-issue the ajax call to poll again.
Also, it's not a great idea to do this in a recursive manner. I would suggest doing this in a for loop instead.
You are calling your function recursively and as the session variable does not change between the function calls, if it goes to the else part the first time, it will go there every time, creating a never ending loop.
By the way, if you want to use polling, you should set a timer in the client part (javascript) and not use a recursive function on the server side.
There are a few things you want to look at when performing any long polling techniques.
You need to exit after some predefined time period. Waiting on the server until you have something to respond with will lead you to execution timeouts.
Know what is going on with your SESSION data. PHP by default will use file based sessions and locks the file during the course of the request (unless you intervine)

php service executing sql commands using jquery ajax

<?php
header('Cache-Control: no-cache, must-revalidate');
header('Content-type: application/json');
$mysql = mysql_connect('corte.no-ip.org', 'hostcorte', 'xxxx');
mysql_select_db('fotosida');
if((isset($_POST['GetPersons'])))
{
if(isset($_POST['ID'])) {
$query = sprintf("SELECT * FROM persons WHERE id='%s'",
mysql_real_escape_string($_POST['ID']));
} else {
$query = "SELECT * FROM persons";
}
$res = mysql_query($query);
while ($row = mysql_fetch_assoc($res)) {
for ($i=0; $i < mysql_num_fields($res); $i++) {
$info = mysql_fetch_field($res, $i);
$type = $info->type;
if ($type == 'real')
$row[$info->name] = doubleval($row[$info->name]);
if ($type == 'int')
$row[$info->name] = intval($row[$info->name]);
}
$rows[] = $row;
}
echo json_encode($rows);
}
mysql_close($mysql);
?>
This works ok for generating a json object based on a database query. Im not very familiar with PHP, so i would like some feedback from you before i proceed with this. Is this a good way of calling the database using ajax? Other alternatives? Frameworks maybe?Are there any security problems when passing database queries like UPDATE, INSERT, SELECT etc using an ajax HTTPPOST? Thanks
To simplify CRUD operations definitely give REST a read.
As mentioned, stop using the # (AKA "shut-up") operator in favor of more robust validation:
if(isset($_GET['key'])){
$value = $_GET['key'];
}
Or some such equivalent.
Using JavaScript/AJAX, aggregate and send your request data, such as IDs and other parameters, from the form fields into a JSON object. Not the built query. The only time the client should be allowed to manipulate directly executed SQL is if you're creating an web based SQL client. Architect your URLs meaninfully (RESTful URLs) so that your HTTP request can be formed as:
GET users/?id=123
DELETE photos/?id=456
Or alternatively:
GET users/?id=123
GET photos/?method=delete&id=456
Server-side, you're going to receive these requests and based on parameters from the session, the request, etc., you can proceed by firing parametrized queries:
switch($method){
case 'get':
$sql = 'SELECT * FROM `my_table` WHERE `id` = :id';
break;
case 'delete':
$sql = 'DELETE FROM `my_table` WHERE `id` = :id';
break;
default:
// unsupported
}
// interpolate data from $_GET['id'] and fire using your preferred
// database API, I suggest the PDO wrapper.
See PDO
Generate output as necessary, and output. Capture on client-side and display.
Always validate and filter user input. Never send and execute raw SQL queries, or concatenate raw user input into SQL queries.
With regard to your question, here's a possible snippet:
(Note -- I haven't tested it, nor rigorously reviewed it, but it should still serve as a guide -- there is a lot of room for improvement, such as refactoring much of this logic into reusable parts; functions, classes, includes, etc.)
header('Cache-Control: no-cache, must-revalidate');
header('Content-type: application/json');
$error = array();
// get action parameter, or use default
if(empty($_POST['action']))
{
$action = 'default_action';
}
else
{
$action = $_POST['action'];
}
// try to connect, on failure push to error
try
{
$pdo = new PDO('mysql:dbname=fotosida;host=corte.no-ip.org', 'hostcorte', 'xxxx');
}
catch(Exception $exception)
{
$error[] = 'Error: Could not connect to database.';
}
// if no errors, then check action against supported
if(empty($error))
{
switch($action)
{
// get_persons action
case 'get_persons':
try
{
if(!isset($_POST['id']))
{
$sql = 'SELECT * FROM `persons`';
$stm = $pdo->prepare($sql);
$stm->execute();
}
else
{
$sql = 'SELECT * FROM `persons` WHERE `id` = :id';
$stm = $pdo->prepare($sql);
$stm->execute(array(
'id' => (int) $_POST['id'],
));
}
$rows = array();
foreach($stm->fetchAll() as $row)
{
$rows[] = $row;
}
}
catch(Exception $exception)
{
$error[] = 'Error: ' . $exception->getMessage();
}
break;
// more actions
case 'some_other_action':
// ...
break;
// unsupported action
default:
$error[] = 'Error: Unsupported action';
break;
}
}
// if errors not empty, dump errors
if(!empty($error))
{
exit(json_encode($error));
}
// otherwise, dump data
if(!empty($rows))
{
exit(json_encode($rows));
}
You can't do that. Sending database queries from the client is a huge security risk! What if he sends DROP TABLE fotosida as query?
You should always validate and sanitize data coming from the client before you do anything with it. Identify your use-cases and provide access to them with a clearly defined interface.
Update: To elaborate a bit about the interface you define. Say you're creating a gallery. Let's assume you have several use-cases:
Get a list of all images
Delete an image from the gallery
Upload an image to the gallery
There are different ways to do this, but the simplest way (for a beginner in PHP programming) is proably to have a PHP script for every case.
So you'll have:
imageList.php?gallery=1 that will return a list of all images in the gallery with ID 1
deleteImage.php?image=46 will delete the image with ID 46
uploadImage.php parameters will be passed via multipart POST and should be a uploaded file and the ID of the gallery where the image should be added to.
All these scripts need to make sure that they are receiving valid parameters. Eg. the ID should be a number, uploaded file needs to be checked for validity etc.
Only expose the needed functionality via your interface. This makes it much more secure and also better understandable for other users.
Like the other answers above, i agree that this is just asking for an injection attack (and probably other types). Some things that you can do to prevent that and enhance security in other ways could be the following:
1 Look for something suspicious with your response handler.
Lack of a query variable in the post, for instance, doesn't make sense, so it should just kill the process.
#$_POST["query"] or die('Restricted access');
2 Use preg_match to sanatize specific fields.
if (!preg_match("/^[a-zA-Z0-9]+$/", $_POST[query])){
die('Restricted access');
}
3 Use more fields, even if they are semi-meaningless and hidden, to add more reasons to kill the process through their absence, or lack of a certain text pattern (optional).
4 You shouldn't send a complete query through the POST at all. Just the elements that are necessary as input from the user. This will let you build the query in PHP and have more control of what actually makes it to the final query. Also the user doesn't need to know your table names
5 Use mysql_real_escape_string on the posted data to turn command characters into literal characters before entering data into a db. This way someone would have a last name of DROP TABLE whatever, instead of actually dropping table whatever.
$firstname = mysql_real_escape_string($_POST[fname]);
$lastname = mysql_real_escape_string($_POST[lname]);
$email = mysql_real_escape_string($_POST[email]);
$sql="INSERT INTO someTable (firstname, lastname, email)
VALUES('$firstname','$lastname','$email')";
6 Last, but not least, be creative, and find more reasons to kill your application, while at the same time giving the same die message on every die statement (once debugging is done). This way if someone is hacking you, you don't give them any feedback that they are getting through some of your obstacles.
There's always room for more security, but this should help a little.
You shouldn't trust your users so much! Always take into account, when working with Javascript, that an user could edit your calls to send what (s)he wants.
Here you are taking the query from the GET parameters and executing it without any kind of protection. How can you trust what $_GET['query'] contains? A way to do this would be to call a php page with some parameters through ajax, validate them using PHP and then execute a query built on the parameters you get, always thinking about what the values of such parameters could be.

Bottlenecks slowing some part of my script

I have a script that perform the following steps
A user logs in, adds an SMS message and specifies recipients. That information is added to "queued message table";
Some process sends the messages using an API and messages are moved to "sent message table";
A delivery report comes and messages are deleted from "sent message table" and a log entry referencing sent messages is added to "sent message log table".
when a large quantity of messages is queued up in the "queued message table", steps (2) and (3) take a long time,
Before message is pushed to the API, a random unique id is generated for every recipients for later referencing when retrieving report, that id is used to table ' sent message log table'.
Below is the sample script
<?php
class Message {
/*
* random unique id for mobile number
*/
protected $mobile_ids = array();
public function add_unique_id($id, $mobile)
{
$this->mobile_ids[] = array($id, $mobile);
}
public function get_unique_id()
{
return $this->mobile_ids;
}
// The method that generated the xml for API
public function makeXML($param,$multi_part=false)
{
$xmlString =
"<SMS>
<authentification>
<username>sss</username>
<password>sss</password>
</authentification>
<message>
<sender>sender</sender>";
if($multi_part == "longSMS") $xmlString .= "<type>longSMS</type>";
$xmlString .= "<text>{$param['text']}</text></message><recipients>";
// Array of mobile numbers came from $param
$phone_numbers = $param['numbers'];
// Loop through the array and generate <gsm messageId='0001'>mobile</gsm>
foreach($phone_numbers as $mobile) {
// Generate id for mobile
$msg_id = $this->make_random_int();
/**
* This is the slow part of the script,
* IDs are added to the array for logging into the database
* When message is sent, i looped through the id and created a log for this message
**/
$this->add_unique_id($msg_id, $mobile);
$xmlString .= "<gsm messageId=\"{$msg_id}\">{$mobile}</gsm>";
}
$xmlString .= "</recipients></SMS>";
return $xmlString;
}
/**
* This is the method that created the log
* Log the sms
* You will need to call $msgid = $this->update_db('the sms')
* return value of $msgid is last_insert_id
*/
public function log_sms($msgid) {
// Log the currently sent message
$userData = array();
$now = date('Y-m-d H:i:s');
foreach ($this->mobile_ids as $data) {
$userData[] = "('{$msgid}', '{$data[0]}', '{$data[1]}', 'QUEUED', '0000-00-00', '0000-00-00', '{$now}')";
}
$query = 'INSERT INTO sent_sms_log (txtId,msgID,mobile,status,sentdate_time,deliver_date_time,sysdate_time) VALUES' . implode(',', $userData);
$this->ci->db->query($query);
$this->mobile_ids = array(); // reset the array
}
// Make random int
protected function make_random_int() {
$this->ci->load->helper('string');
$int = random_string('numeric', 12);
return $int;
}
/**
* Update database after sms sent
* #return int
*/
public function update_db($msg, $owner, $qid=0) {
$data = array('qid'=> $qid, 'sms' => $msg, 'date_time' => date('Y-m-d H:i:s'), 'owner' => $owner);
$this->ci->db->insert('f_sent_sms', $data);
return $this->ci->db->insert_id();
}
}
I'm guessing it could likely be the api you're working with. I've had to work with apis for different services that were extremely slow. Maybe try profiling different parts of the code with the benchmark class:
http://codeigniter.com/user_guide/libraries/benchmark.html
That'll be a quick and easy way to find the slowest parts of the code.
I'm guessing this is running on some kind of a loop right now? Instead of inserting an unknown number of records one at a time, check out the insert_batch() method for Active Record in the User Guide http://codeigniter.com/user_guide/database/active_record.html You can use one database call to insert all of your records. Instead of the loop inserting the data into the database, all the loop would have to do is build an array of all of the data that will be inserted. After the loop is done, run insert_batch('f_sent_sms', $my_data) for the array you just built.
It would be a good idea to benchmark it all too (before and after) as #Matthew already said.

Categories