I am trying to detect status of invoice from a json file, then if the status is a confirmed payment, update the status and write the json to a new location, then unlink the existing json location.
<?php
// get posted variables or die;
if (isset($_POST['num'])) {
$invoice = strip_tags($_POST['num']);
$filename = $invoice.'.json';
} else {
die;
}
if (isset($_POST['status'])) {
$status = strip_tags($_POST['status']);
} else {
die;
}
// get existing invoice
$content = file_get_contents('data/'.$invoice.'.json');
$data = json_decode($content, true);
// read json into variables
$email = $data['email'];
$id = $data['id'];
$addr = $data['tac_address'];
$os = $data['os'];
$exp = $data['experience'];
$hosting = $data['type'];
if (isset($data['telegram']) && $data['telegram'] != '') { $telegram = $data['telegram']; } else { $telegram = ''; }
if (isset($data['linkedin']) && $data['linkedin'] != '') { $linkedin = $data['linkedin']; } else { $linkedin = ''; }
if (isset($data['pay_status']) && $data['pay_status'] != '' && $data['pay_status'] == $status) { $status = $data['pay_status']; }
$payment_addr = $data['bitcoin'];
$payment_value = $data['value'];
$payment = substr($payment_value, 0, -4);
// turn variables into json array
$arr = array(
'id' => $invoice,
'email' => $email,
'tac_address' => $addr,
'os' => $os,
'experience' => $exp,
'type' => $hosting,
'telegram' => $telegram,
'linkedin' => $linkedin,
'bitcoin' => $payment_addr,
'value' => $payment_value,
'pay_status' => $status
);
$json = json_encode($arr);
// check status if paid save output to new location and delete old file
if ($status == 'Confirmed Payment') {
file_put_contents('paid_data/'.$filename, $json);
unlink('data/'.$filename);
}
The problem I am facing is that file_put_contents('paid_data/'.$filename, $json); ends up a file with a bunch of NULL variables. If I remove the unlink the variables save just fine, when I add it back the variables are all NULL.
So how can I verify file_put_contents takes place before the unlinking happens?
Also.... WHY does this happen? Isn't php supposed to be linear and shouldn't file_put_contents finish before the next line is carried out? Everything I have read about file_put_contents suggests as much. So why does the unlink take place before writing the content to a new location?
I still hope for a better answer, but so far this is my working solution to the problem. I changed the final if statement to the following. This seems to solve the issue - but there really has to be a better way than this. This feels very "hacky".
if ($status == 'Confirmed Payment') {
file_put_contents('paid_data/'.$filename, $json);
$i = 0;
while ($i < 1000) {
$i++;
if (file_exists('paid_data/'.$filename)) {
unlink('data/'.$filename);
break;
}
}
}
After mimicking your file structure and seeding a few examples, I was able to execute your code as is with the expected results. However, file_put_contents willreturn false on failure, so you might try something like this:
if ($status == 'Confirmed Payment') {
if(!file_put_contents('paid_data/'.$filename, $json);){
print_r(error_get_last());
die;
}
unlink('data/'.$filename);
}
Your code as originally written should be fine, as far as I can see. Usually when I see the kind of behavior you're describing, the problem is that the script itself is being called twice (or more) and overlapping calls are manipulating the same file.
I would definitely put in some debugging statements to verify this; I don't know your environment, but a simple line written to a log will probably be enlightening.
Related
This is just a slight update from a question that was solved at an earlier date. I am simply trying to get 2 city names into variables from 2 different JSON results. This works good but every now and then one or the both sometimes returns nothing yet nothing changes?
Am I doing something wrong or is there a way to loop it until I get the result?
Sorry to be a pain but I really cannot see why its hit and miss?
The working code in PHP that runs the 2 queries and gets the result sometimes!
$p_lat = "52.406822";
$p_lng = "-1.519693";
$d_lat = "50.87626460000001";
$d_lng = "-0.3717470999999932";
$county = "";
$town = "";
$d_county = "";
$d_town = "";
$result = #file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?latlng=".$p_lat.",".$p_lng."&sensor=true" );
if ($result === FALSE) {
//manage exception from file_get_contents call
} else {
$geocodedinfo = json_decode($result);
if ($geocodedinfo->status == "OK") {
$county = "";
$town = "";
foreach ($geocodedinfo->results[0]->address_components as $addrcomps) {
if ( $addrcomps->types[0] == 'postal_town')
$town = $addrcomps->long_name;
}
}
}
$result = #file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?latlng=".$d_lat.",".$d_lng."&sensor=true" );
if ($result === FALSE) {
//manage exception from file_get_contents call
} else {
$geocodedinfo = json_decode($result);
if ($geocodedinfo->status == "OK") {
$county = "";
$d_town = "";
foreach ($geocodedinfo->results[0]->address_components as $addrcomps) {
if ( $addrcomps->types[0] == 'postal_town')
$d_town = $addrcomps->long_name;
}
}
}
echo $town;
echo "<br>";
echo $d_town;
It is fixed. I had to add HTTPS to it and include a KEY. I did not to start with as it was working without one!! Oh well.
$result = #file_get_contents("https://maps.googleapis.com/maps/api/geocode/json?latlng=".$p_lat.",".$p_lng."&sensor=true&key=KEYHERE&" );
Thanks anyway
When I tried to print $result:
$result = #file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?latlng=".$p_lat.",".$p_lng."&sensor=true" );
echo "<pre>";
print_r(json_decode($result));
exit;
Below is the response:
stdClass Object
(
[error_message] => You have exceeded your daily request quota for this API. We recommend registering for a key at the Google Developers Console: https://console.developers.google.com/apis/credentials?project=_
[results] => Array
(
)
[status] => OVER_QUERY_LIMIT
)
So try to register your application first. Which will ultimately solve your problem.
I'd like some help please, if its possible.
I have created two functions in order to display some messages when is set a $_GET after a redirect.Here's the code:
function display(){
if(isset($_GET['cnf_upd']) && $_GET['cnf_upd'] == '1'){
$value = "The update was successful!";
$type = "confirm";
construct_the_div($value, $type);
}
if(isset($_GET['err_upd']) && $_GET['err_upd'] == '1'){
$value = "The Update failed.";
$type = "error";
construct_the_div($value, $type);
}
if(isset($_GET['cnf_del']) && $_GET['cnf_del'] == '1'){
$value = "Deleted completely.";
$type = "confirm";
construct_the_div($value, $type);
}
if(isset($_GET['err_del']) && $_GET['err_del'] == '1'){
$value = "Unable to delete.";
$type = "error";
construct_the_div($value, $type);
}
}
function construct_the_div($value, $type){
// creating a div to display the message results
$div = "<div class=\"{$type}Msg\">\n";
$div .= "<p>{$value}</p>\n";
$div .= "</div><!-- end of {$type}Msg -->\n";
echo $div;
}
What I'd like to make is to try to improve the display function, as it gets longer and longer, so that there whould be only one (or two at most) if statement(s) if possible. So the value of the GET will be dynamicly inside the if condition and also if it has the preffix 'cnf_' it wil be a 'confirmMsg' and if it has the preffix 'err_' it wil be a 'errorMsg'.
Is it possible to make something like this???
function display() {
$messages = array(
'cnf_upd' => 'The update was successful!',
'cnf_err' => 'The Update failed.!',
// ...
// add all error and confirm there
// ...
);
foreach($_GET as $key => $value) {
if(strpos($key, 'cnf_')===0) {
$type = 'confirm';
$value = isset($messages[$key])
? $messages[$key]
: $key;
construct_the_div($value, $type);
}
if(strpos($key, 'err_')===0) {
$type = 'error';
$value = isset($messages[$key])
? $messages[$key]
: $key;
construct_the_div($value, $type);
}
}
}
The approach is not correct, it seems that only one message should occur at once (there cannot be "deleted completely" and "unable to delete" at once).
Try construct the parameters this way: ?msg=upd&msgType=cnf
function display(){
if (isset($_GET['msg']) && isset($_GET['msgType']))
{
$messages = array('cnf_upd'=>'The update was successful!',
'err_upd'=>'The update failed!',
'cnf_del'=>'The deletion was successful!',
'cnf_upd'=>'The deletion failed!',
);
if (isset($messages[$_GET['msgType'].'_'.$_GET['msg']))
construct_the_div($messages[$_GET['msgType'].'_'.$_GET['msg']], htmlspecialchars($_GET['msgType']));
}
there is still much to improve, but for start this is cleaner and safer.
I'm going to propose a different solution. Instead of setting different parameters in $_GET based on the message to be sent, set one parameter and parse its value.
// Start by setting integer constants:
define(CNF_UPD, 1);
define(ERR_UPD, 2);
define(CNF_DEL, 3);
define(ERR_DEL, 4);
Then when you set the value un $_GET, use the constant:
// Build the URL with a deletion error...
header("Location: http://example.com/script.php?msg=" . ERR_DEL);
Finally, use a switch to parse them
if (isset($_GET['msg'])) {
switch ($_GET['msg']) {
case CNF_UPD:
// Updated...
break;
case ERR_UPD:
// failed...
break;
// etc...
default:
// invalid code.
}
}
If you use a pattern of confirm/error/confirm/error for your integer constants, you can determine which it is by taking $_GET['msg'] % 2. Odd numbers are confirmations, evens are errors. There are of course many other ways you could lay this out, I just happen to have typed them in the alternating order you used. You could also do positive integers for confirmations and negatives for errors, for example.
$type = $_GET['msg'] % 2 == 1 ? $confirm : $error;
This is easily expanded to use multiple messages as well. Since they are integer values, you can safely construct a comma-separated list and explode() them when received.
$messages = implode(array(ERR_DEL,CNF_UPD));
header("Location: http://example.com/script.php?msg=$messages");
Unless you can somehow generate $value and $type based on the $_GET parameter (which I can't see how you would do), you could do something like:
$messages = array();
$messages[] = array('id' => 'cnf_upd', 'value' => 'The update was successful!', 'type' => 'Confirm');
$messages[] = array('id' => 'err_upd', 'value' => 'The Update failed.', 'type' => 'error');
...
foreach ($messages as $message) {
if(isset($_GET[$message['id']]) && $_GET[$message['id']] == '1'){
construct_the_div($message['value'], $message['type']);
}
}
I have 2 questions
1.) how to write update_defile($array_value){...} function?
define_file.php
<?php
define("FIST_NAME", "something1");
define("LAST_NAME", "something2");
define("ADDRESS", "something3");
?>
"something" is not a constant value that can be change every method Call(update_defile($array_value)
value set
$array_value = ("FIST_NAMe" => "duleep", "LAST_NAME" => "dissnayaka", "AGE" => "28" );
after call method(update_defile($array_value){.....}) "define_file.php"
file want to be look like bellow
<?php
define("FIST_NAME", "duleep");
define("LAST_NAME", "dissnayaka");
define("ADDRESS", "something3");
define("AGE", "28");
?>
2).
My datbase is Oracle. I already saved configuration value in the data base but frequently use these configuration value for my application. So i get value form database and save in the define_file.php as increase performance(down rate database call) but I'm not sure i can increase performance keep configuration value in the PHP file please explain. what is the best way increase performance my application and other alternative solutions welcome.
Why cant u use session to store such values , then u can access and modify from anywhere
in the script.
<?php
session_start();
$_SESSION["FIST_NAME"]= "something1";
$_SESSION["LAST_NAME"]= "something2";
$_SESSION["ADDRESS"]= "something3";
?>
public function update($form_config_arr)
{
if( (is_readable($config_file_path)) && is_writable($config_file_path))
{
if(!$config_old_file_content = file_get_contents($config_file_path))
{
throw new Exception('Unable to open file!');
}
$i = 0;
$config_old_arr = array();
$config_new_arr = array();
foreach ($form_config_arr as $constant => $value){
$config_old_line = $this->getLine($constant);
$config_old_arr[$i] = $config_old_line;
if(($value == 'true') || ($value == 'false')){
$config_new_arr[$i] = "define ( '$constant', $value );\n";
}else{
$config_new_arr[$i] = "define ( '$constant', '$value' );\n";
}
$i++;
}
$config_new_file_content = str_replace($config_old_arr, $config_new_arr, $config_old_file_content);
$new_content_file_write = file_put_contents($config_file_path, $config_new_file_content);
foreach ($config_new_arr as $constant => $value)
{
echo $value.'<br/>';
}
return true;
}else{
throw new Exception('Access denied for '.$config_file_path);
return false;
}
}
/**
*
* #param string $constant
* #return string
*/
private function getLine($constant)
{
$match_line = '';
$config_file = fopen($config_file_path, "r");
if($config_file)
{
//Output a line of the file until the end is reached
$i = 0;
while(!feof($config_file))
{
$i++;
$config_old_line = fgets($config_file);
$pos = strpos($config_old_line, $constant);
if( $pos !== false )
{
$match_line= $config_old_line;
}
}
fclose($config_file);
return $match_line;
}else{
throw new Exception('Unable to open file!');
}
}
What you are trying to do is edit a file.
Simply create another php script: updater.php
It should poll the database, fetch the values and update the values in define_file.php
Look for php file handling functions here: http://www.w3schools.com/php/php_file.asp
Like the title says, PHP is really confusing me on a simple if comparison statement that's returning the opposite of what it should be returning. I'm trying to compare 2 datetime's that are first converted to strings:
//Fetched db query, this returns 2012-06-23 16:00:00
$databaseDateTime = strtotime($row['time']);
//This now returns 1340481600
//today's date and time I'm comparing to, this returns 2012-06-22 17:14:46
$todaysDateTime = strtotime(date("Y-m-d H:i:s"));
//this now returns 1340399686
Great, everything works perfect so far. Now here's where things get hairy:
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
And this returns 'past', which of course it shouldn't. Please tell me I'm missing something. My project kind of depends on this functionality being airtight.
**EDIT***
Thanks guys for taking the time to help me out. Let me post the entire code because a few of you need more context. The request is coming from an IOS5 to my backend code and json is being sent back to the phone.
<?php
//all included files including $link to mysqli_db and function sendResponse()
function getEvents($eventType, $eventArray) {
global $link;
global $result;
global $i;
global $todaysDateTime;
foreach ($eventArray as $key => $value) {
$sqlGetDeal = mysqli_query($link, "SELECT time FROM deals WHERE id='$value' AND active='y' LIMIT 1") or die ("Sorry there has been an error!");
while ($row = mysqli_fetch_array($sqlGetDeal)) {
//compare times to check if event already happened
$databaseDateTime = strtotime($row['time']);
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
$result[$i] = array(
'whenDeal' => $eventType,
'time' => $databaseDateTime,
);
$i++;
}//end while
}//end foreach
}
if (isset($_GET['my'])) {
//$_GET['my'] comes in as a string of numbers separated by commas e.g. 3,2,6,3
$myDeals = preg_replace('#[^0-9,]#', '', $_GET['my']);
$todaysDateTime = strtotime(date("Y-m-d H:i:s"));
$result = array();
$kaboomMy = explode(",", $myDeals);
$i = 1;
if ($myEvents != "") {
getEvents('future', $kaboomMy);
}//end if
sendResponse(200, json_encode($result));
} else {
sendResponse(400, 'Invalid request');
} //end $_POST isset
?>
Found a quick hack around the issue. I just added a local variable to my function and rearranged my compare statement
//added local variable $eventTyppe to function
$eventTyppe;
changed compare from:
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
to:
if ($todaysDateTime < $databaseDateTime ) {
$eventTyppe = $eventType;
} else {
$eventTyppe = 'past';
}
Notice if I rearrange compare:
if ($databaseDateTime < $todaysDateTime ) {
$eventTyppe = 'past';
} else {
$eventTyppe = $eventType;
}
I still get the same error. This is the weirdest thing I've ever seen and the first PHP bug I've run into (I'm assuming it's a PHP bug).
Could you print the values of the times right before this line?
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
Since that one is declared as global I'm wondering if is it coming back incorrectly.
I have a script that is designed to parse XML postbacks from Ultracart, right now just dumps it into a MySQL table. The script works fine if I point it to a XML file on my localhost but using 'php://input' it doesn't seem to grabbing anything. My logs show apache returning 200 after the post so I have no idea what could be wrong or how to drill down the issue.. here's the code:
$doc = new DOMDocument();
$doc->loadXML($page);
$handle = fopen("test2/".time().".xml", "w+");
fwrite($handle,trim($page)); // it doesn't save this either :'(
fclose();
require_once('includes/database.php');
$db = new Database('localhost', 'user', 'password', 'db_name');
$data = array();
$exports = $doc->getElementsByTagName("export");
foreach ($exports as $export) {
$orders = $export->getElementsByTagName("order");
foreach($orders as $order) {
$data['order_id'] = $order->getElementsByTagName("order_id")->item(0)->nodeValue;
$data['payment_status'] = $order->getElementsByTagName("payment_status")->item(0)->nodeValue;
$date_array = explode(" ",$order->getElementsByTagName("payment_date_time")->item(0)->nodeValue);
if ($date_array[1] == 'JAN') { $date_array[1] = '01'; }
if ($date_array[1] == 'FEB') { $date_array[1] = '02'; }
if ($date_array[1] == 'MAR') { $date_array[1] = '03'; }
if ($date_array[1] == 'APR') { $date_array[1] = '04'; }
if ($date_array[1] == 'MAY') { $date_array[1] = '05'; } // converts Ultracart date to
if ($date_array[1] == 'JUN') { $date_array[1] = '06'; } // MySQL date
if ($date_array[1] == 'JUL') { $date_array[1] = '07'; }
if ($date_array[1] == 'AUG') { $date_array[1] = '08'; }
if ($date_array[1] == 'SEP') { $date_array[1] = '09'; }
if ($date_array[1] == 'OCT') { $date_array[1] = '10'; }
if ($date_array[1] == 'NOV') { $date_array[1] = '11'; }
if ($date_array[1] == 'DEC') { $date_array[1] = '12'; }
$data['payment_date'] = $date_array[2]."-".$date_array[1]."-".$date_array[0];
$data['payment_time'] = $date_array[3];
//... we'll skip this, there are 80 some elements
$data['discount'] = $order->getElementsByTagName("discount")->item(0)->nodeValue;
$data['distribution_center_code'] = $order->getElementsByTagName("distribution_center_code")->item(0)->nodeValue;
}
}
}
$db->insert('order_history',$data);
} else die('ERROR: Token Check Failed!');
Without seeing the code above that point, I'd suggest that you dump the output straight out and see if you're actually receiving the XML. I doubt the problem is with your parsing, but with receiving the postback. Looking at the ultracart documentation, it looks to me like they aren't passing the the body of the xml in as a post parameter, but probably as an HTTP PUT which is fairly whacky.
http://php.net/manual/en/features.file-upload.put-method.php
I'd wager on most shared hosting etc, PUT support is pretty limited or not supported by default. I'd look there first.
Josh
The script works fine if I point it to a XML file on my localhost but using 'php://input' it doesn't seem to grabbing anything.
Why would you expect php://input to "grab anything"? You can use php://input only to read from the standard input if PHP is being run from the command line or to fetch the request data (e.g. POST or PUT HTTP request data), except for a multipart POST.