Script dies, I'm not sure why - php

I'm trying to parse a 6,000 line 500 KB file into an array so I can import the data into our system. The problem is that the script stops executing somewhere between lines 3000-4000. There are no breaks in the code, we use it on other imports. Any ideas on why this might be happening and what I can do to prevent it?
/**
* Takes a seperated value string and makes it an array
* #param $delimiter string The delimiter to be seperated by, usually a comma or tab
* #param $string string The string to seperate
* #return array The resulting array
*/
public function svToArray ($delimiter, $string) {
$x = 0;
$rowList = array();
$splitContent = preg_split("#\n+#", trim($string));
foreach ($splitContent as $key => $value) {
$newData = preg_split("#".$delimiter."#", $value);
if ($x == 0) {
$headerValues = array_values($newData);
} else {
$tempRow = array();
foreach ($newData as $rowColumnKey => $rowColumnValue) {
$tempRow[$headerValues[$rowColumnKey]] = $rowColumnValue;
}
$rowList[] = $tempRow;
}
$x++;
}
return $rowList;
}
UPDATE:
Error reporting is enabled. I've started using a file that's only 130KB at 1,500 lines and it does the same thing...
When I add debug code as in the following example nothing echoes at all unless I put an exit after the echo "test<br/>";
public function svToArray ($delimiter, $string) {
$x = 0;
$rowList = array();
$splitContent = preg_split("#\n+#", trim($string));
echo "test<br/>";
foreach ($splitContent as $key => $value) {
$newData = preg_split("#".$delimiter."#", $value);
if ($x == 0) {
$headerValues = array_values($newData);
} else {
$tempRow = array();
foreach ($newData as $rowColumnKey => $rowColumnValue) {
$tempRow[$headerValues[$rowColumnKey]] = $rowColumnValue;
}
$rowList[] = $tempRow;
}
$x++;
}
echo "test";
$this->tru->debug($rowList);
exit;
return $rowList;
}
UPDATE
If I comment out $tempRow[] = $rowColumnValue; then it echoes everything fine....

Probably it just timeouts. Does it always stop after X seconds?
Try setting the max execution time higher: set_time_limit(900) at the top of your pages.
You can check the max execution time in your phpinfo():
1. Create a new php page with
2. Search for max_execution_time

Have you looked at the files? Is there a line with too many delimiters? Also, what are all the "#" about?
My best guess is that you're hitting a line where $headerValues[$rowColumnKey] is not defined.

What about $rowColumnKey and $rowColumnValue ?
They are not defined in the function.

Make sure that you have error reporting set, put this on top of your php file:
ini_set('display_errors', true);
error_reporting(E_ALL);
Also you can extend the script's execution time:
ini_set('max_execution_time', 50000);

About the only time I've a php script die, with no output and no errors is when it runs out of memory. It doesn't look like your script would use much memory, but I would check to make sure that the memory limit for php is high enough.

Are you sure that you are iterating through the returned array instead of simply trying to print it? (The issue may be outside of the function rather than within it.)
Also...
`exit;
return $rowList;`
Try removing the 'exit;' line and see if that changes anything.
Also, $splitContent is not defined as an array before being used, but preg_split is going to return an array. (This should not impact your results, but it is safe to do so.)
Why are you using $key => $value pairs when you cannot be sure of what will be within the string? If we could see an small example of the content of $string, we might be able to adjust this function to work better.
The # should be replaced with /, but that may simply be a formatting issue.
$newData should be defined as an array before being used just to be safe even though that is not causing your issue.

If you can, increase maximum execution time in php.ini.. also increase the maximum memory amount for each instance.. checking error logs of your webserver could also help.

It appears as though there was too much output to the output buffer, causing the page to show nothing at all.

Related

How to get variables from a different PHP file without executing the code?

I am trying to loop through all the php files listed in an array called $articleContents and extract the variables $articleTitle and $heroImage from each.
So far I have the following code:
$articleContents = array("article1.php", "article2.php"); // array of all file names
$articleInfo = [];
$size = count($articleContents);
for ($x = 0; $x <= $size; $x++) {
ob_start();
if (require_once('../articles/'.$articleContents[$x])) {
ob_end_clean();
$entry = array($articleContents[$x],$articleTitle,$heroImage);
array_push($articlesInfo, $entry);
}
The problem is, the php files visited in the loop have html, and I can't keep it from executing. I would like to get variables from each of these files without executing the html inside each one.
Also, the variables $articleTitle and $heroImage also exist at the top of the php file I'm working in, so I need to make sure the script knows I'm calling the variables in the external file and not the current one.
If this is not possible, can you please recommend an alternative method?
Thanks!
Don't do this.
Your PHP scripts should be for your application, not for your data. For your data, if you want to keep it file-based, use a separate file.
There are plenty of formats to choose from. JSON is quite popular. You can use PHP's built-in serialization as well, which has support for more PHP-native types but is not as portable to other frameworks.
A little hacky but seems to works:
$result = eval(
'return (function() {?>' .
file_get_contents('your_article.php') .
'return [\'articleTitle\' => $articleTitle, \'heroImage\' => $heroImage];})();'
);
Where your_article.php is something like:
<?php
$articleTitle = 'hola';
$heroImage = 'como te va';
The values are returned in the $result array.
Explanation:
Build a string of php code where the code in your article scripts are wrapped inside a function that returns an array with the values you want.
function() {
//code of your article.php
return ['articleTitle' => $articleTitle, 'heroImage' => $heroImage];
}
Maybe you must do some adaptations to the strings due <?php ?> tags placements.
Anyway, this stuff is ugly. I'm very sure that it can be refactored in some way.
Your problem (probably) comes down to using parentheses with require. See the example and note here.
Instead, format your code like this
$articlesInfo = []; // watch your spelling here
foreach ($articleContents as $file) {
ob_start();
if (require '../articles/' . $file) { // note, no parentheses around the path
$articlesInfo[] = [
$file,
$articleTitle,
$heroImage
];
}
ob_end_clean();
}
Update: I've tested this and it works just fine.

n factorial issue with large number

I have written the following code for finding n!. I am running this through CLI.
<?php
$handle = fopen("php://stdin", "r");
$number = (int) trim(fgets($handle));
$fact = calcFactorial($number);
echo $fact . "\n";
function calcFactorial($number) {
if ($number < 2) {
return 1;
} else {
return $number * calcFactorial($number - 1);
}
}
fclose($handle);
?>
The above code is working fine. But there are two issues with two different PHP installations.
On one PC I get,
Fatal error: Maximum function nesting level of '100' reached,
aborting!
To correct above problem I find the solution here. Is this the correct way to have a solution? Because it depends on a particular Default Value of 'xdebug.max_nesting_level' .
On other PC I get,
INF
So what is the best approach to tackle this issue?
P.S.: I have gone through various solutions throughout this website but I am not able to conclude.
UPDATE: There is one function suggested. But can it be done without using any kind of function?
Nesting limit:
if the calcFactorial() can by non-recursive then you can change it to this:
function calcFactorial($number){
if($number<2){
return 1;
}
$ret = 1;
for($i=2;$i<=$number;$i++){
$ret = $ret*$i;
}
return $ret;
}
if has to be recursive you never be able to calc factorial of number bigger then Maximum function nesting level.
INF:
That means PHP thinks number is infinitive (to big to store in memory) ... i think (not sure) that answer is bigger than PHP_INT_MAX ...
You can confirm this by echo is_infinite($number);
you can try solve this with storing numbers as strings (of digits) or arrays (of digits) and than write some function to make multiplication of this strings (arrays) but it is not easy to do

Can I retry file_get_contents() until it opens a stream?

I am using PHP to get the contents of an API. The problem is, sometimes that API just sends back a 502 Bad Gateway error and the PHP code can’t parse the JSON and set the variables correctly. Is there some way I can keep trying until it works?
This is not an easy question because PHP is a synchronous language by default.
You could do this:
$a = false;
$i = 0;
while($a == false && $i < 10)
{
$a = file_get_contents($path);
$i++;
usleep(10);
}
$result = json_decode($a);
Adding usleep(10) allows your server not to get on his knees each time the API will be unavailable. And your function will give up after 10 attempts, which prevents it to freeze completely in case of long unavailability.
Since you didn't provide any code it's kind of hard to help you. But here is one way to do it.
$data = null;
while(!$data) {
$json = file_get_contents($url);
$data = json_decode($json); // Will return false if not valid JSON
}
// While loop won't stop until JSON was valid and $data contains an object
var_dump($data);
I suggest you throw some sort of increment variable in there to stop attempting after X scripts.
Based on your comment, here is what I would do:
You have a PHP script that makes the API call and, if successful, records the price and when that price was acquired
You put that script in a cronjob/scheduled task that runs every 10 minutes.
Your PHP view pulls the most recent price from the database and uses that for whatever display/calculations it needs. If pertinent, also show the date/time that price was captured
The other answers suggest doing a loop. A combo approach probably works best here: in your script, put in a few loops just in case the interface is down for a short blip. If it's not up after say a minute, use the old value until your next try.
A loop can solve this problem, but so can a recursive function like this one:
function file_get_contents_retry($url, $attemptsRemaining=3) {
$content = file_get_contents($url);
$attemptsRemaining--;
if( empty($content) && $attemptsRemaining > 0 ) {
return file_get_contents_retry($url, $attemptsRemaining);
}
return $content;
}
// Usage:
$retryAttempts = 6; // Default is 3.
echo file_get_contents_retry("http://google.com", $retryAttempts);

Weird pow() php bug

I have this piece of php code:
$skill_amount = round(pow($rarity,1.25));
It should be noted that $rarity is derived from a query.
I am inputting values like 0,2,4,8,16,32,64 into it.
99% of the time it is working but a small amount of times my users are reporting huge values like:
13771, 77936
What could possibly be causing this?
"What could possibly be causing this?"
A large or unexpected value for $rarity.
If you can inspect all possible values of $rarity, you should do that. Otherwise, you could do some basic debugging.
if ($skill_amount > some sane value) {
// log $skill_amount & $rarity to a file or email
// maybe also some other investigative values, like stuff that assisted the derivation of $rarity
}
No trouble found in this script, so I would agree with the need for sanity checks on $rarity.
<?php // RAY_temp_amy_neville.php
error_reporting(E_ALL);
echo '<pre>';
$range = range(1, 4096);
foreach ($range as $rarity)
{
$skill_amount = round(pow($rarity,1.25));
$out[$rarity] = $skill_amount;
}
print_r($out);

Am I bloating my coding with IF statements?

I was wondering, do too many IF statements bloat coding and when is it okay not to use them?
These two examples both work the same and I'm the only one editing / using the script. Am I teaching myself bad habits by not adding the IF statement?
if ($en['mm_place']) {
$tmp = explode(",", $en['mm_place']);
$en['mm_place'] = $tmp[0].", ".$tmp[1]." ".$tmp[2];
}
is the same as...
$tmp = explode(",", $en['mm_place']);
$en['mm_place'] = $tmp[0].", ".$tmp[1]." ".$tmp[2];
EDIT: using #Francis Avila example I came up with this...
if ($en['mm_wmeet']) {
$tmp = explode(",", $en['mm_wmeet']);
for ($i = 0; $i < count($tmp); $i++) {
$en['mm_wmeet'] = $tmp[$i];
}
}
In this particular example, they are not the same.
If $en['mm_place'] is empty, then $tmp will not have three elements, so your string construction will be bogus.
Actually what you need is probably this:
if (!empty($en['mm_place'])) { // depending on whether you know if this is set and must be a string.
$tmp = explode(',', $en['mm_place'], 3);
if (count($tmp)===3) {
$en['mm_place'] = "{$tmp[0]}, {$tmp[1]} {$tmp[2]}";
}
}
Run PHP with E_NOTICE set, and code in such a way that you don't get any notices. PHP requires an extraordinary amount of discipline to use safely and properly because it has so many sloppy misfeatures. Notices will inform you of most bad practices. You will probably end up using lots of if statements.
if they don't serve any purpose then yes, you're bloating.
In this kind of situation, where you are checking if an array element exists before operating on it, you should keep the if-statement in the code. Here it will only throw a notice if the element is missing, but in the future you definitely could have similar code that will crash if the element is not set.
Edit: Actually those two code samples are not the same. if $en['mm_place'] is null or not set, the first sample will leave it as such while the second will replace it with ", "

Categories