What would cause a php script to just stop without reason? - php

I'm using class.upload.php to upload images to a page. It seems a script that previously worked is now basically stopping part way through without any errors. At each line in the script, I'm echoing a number so I can get an idea at which point it stops, ie:
// save uploaded image with a new name
$foo->file_new_name_body = $image_name;
$foo->Process($save_directory);
if ($foo->processed) {
echo 'original image copied 1';
} else {
echo 'error 1: ' . $foo->error;
}
echo '1'; $foo->file_new_name_body = $image_name . '_medium';
echo '2'; $foo->image_resize = true;
echo '3'; $foo->image_convert = jpg;
echo '4'; $foo->image_x = 300;
echo '5'; $foo->image_ratio_y = true;
echo '6'; $foo->file_overwrite = true;
echo '7'; $foo->Process($save_directory);
echo '8';
if ($foo->processed) {
echo 'original image copied';
} else {
echo 'error 2: ' . $foo->error;
}
Output:
original image copied 1
1
2
3
4
5
6
7
I have no way to explain it. No errors. No feedback. No further code after echo '7'; is executed. What is going on? How can I debug?
What would be causing this kind of behaviour?
Edit
I was able to fix the issue simply by changing the file being uploaded. It was 2000px wide and when I saved it as a smaller 800px image it completed the process.
I changed the memory as suggested to 40m, however this still doesn't let me process a 2000px wide image which doesn't really make much sense to me. How much memory is needed to deal with files these sizes?

Check your memory limit, I find that if I hit that, PHP can (does?) just quit without saying anything.

Well, I'm no rocket scientist (a) but it seems to me that the most likely cause is that you're not exiting from the call to $foo->Process($save_directory).
You probably need to debug that little beast to find out the reason why.
First step would be to output $save_directory and $image_name to see what they contain.
Second, I would comment out all those flag setting statements and see if it works with just the copy. Then add them back in one at a time until it starts failing again.
It may be that there's either a bug in the conversion code or something wrong with the uploaded image file which causes it to hang. If the latter, perhaps another (simpler) image file may work - it's worth checking.
It's no surprise that it would hang at that point, since all the other statement are simply setting up flags for the process call.
And, as a last resort, you have access to the source. You can simply make your own copy of it (if you don't already have one) and insert debug statements into that to see where it's stopping.
The code for process is actually quite logically laid out. It appears to be a succession of blocks of the form:
if ($this->processed) {
# Attempt to do next stage, setting
# $this->processed to false if there's a problem.
}
So you could just insert an echo statement before each block to find out which block is causing the problem, then start inserting more debug statements within that block until you narrow it down to the actual line.
You may also want to look at the FAQ, especially the bit that states upping the PHP memory limits may assist with larger images. There is also the forums but I see you've already started to go down that route :-)
(a) : What do rocket scientists say in this situation?

What is set to in your php.ini - this for example will show almost any error.
error_reporting = E_ALL & ~E_NOTICE

Related

PHP rename() cannot always find source file (code 2) in Windows environment

My environment is: Windows, MsSQL and PHP 5.4.
My scenario:
I'm doing a small shell script that creates a full backup from my wanted database to a temp folder and then moves it to a new location.
The backup goes fine and the file is created to my temp folder. Then I rename it to the 2nd folder and sometimes it goes ok, sometimes it cannot find the source file.
Of course at this point I know that I could skip the temporary location alltogether, but the actual problem with not finding the file bothers me. Why is it so random and might it also affect other file functions I've written before this one... Also i need to be able to control how and when the files move to the destination.
The base code is simple as it should be (although this is a simplified version of my actual code, since I doubt anyone would be interested in my error handling/logging conditions):
$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";
if($SQLClass->query($query)) {
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
$this->handleError("Moving {$source} to {$destination} failed.");
}
}
else {
die('backup failed');
}
What I have tried is:
I added a file_exists before it and it can't find the source file either, when rename can't.
As the file can't be found, copy() and unlink() will not work either
Tried clearstatcache()
Tried sleep(10) after the sql backup completes
None of these didn't help at all. I and google seem to be out of ideas on what to do or try next. Of course I could some shell_execing, but that wouldn't remove my worries about my earlier products.
I only noticed this problem when I tried to run the command multiple times in a row. Is there some sort of cache for filenames that clearstatcache() won't touch ? It seems to be related to some sort of ghost file phenomena, where php is late to refresh the file system contents or such.
I would appreciate any ideas on what to try next and if you read this far thank you :).
You may try calling system's copy command.
I had once problem like yours (on Linux box) when i had to copy files between two NFS shares. It just failed from time to time with no visible reasons. After i switched to cp (analog of Windows copy) problem has gone.
Surely it is not perfect, but it worked for me.
It might be cache-related, or the mysql process has not yet released the file.
mysql will dump the file into another temp file, first and finally moves it to your temp folder.
While the file is beeing moved, it might be inaccessible by other processes.
First I would try to glob() all the files inside temp dir, when the error appears. Maybe you notice, its still not finished.
Also have you tried to implemente something like 10 retry iterations, with some delay?
$notMoved = 0;
while($notMoved < 10){
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
if ($notMoved++ < 10){
sleep(20);
} else {
$this->handleError("Moving {$source} to {$destination} failed.");
break;
}
}else{
break;
}
}
To bypass the issue:
Don't dump and move
Move then dump :-)
(ofc. your backup store would be one behind then)
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
$this->handleError("Moving {$source} to {$destination} failed.");
}
$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";
if($SQLClass->query($query)) {
//done :-)
}
else {
die('backup failed');
}
Try
$source = "\\server01\temp\backups\file.bak";
$destination = "\\server02\storage\backups\file.bak";
$content = file_get_content($source);
file_put_contents($destination, $content);

Very weird PHP file_exists issue

I run into a very weird situation with file_exists function. The hosting company said their php was configured in CGI mode instead of PHP mode. below is the code. It checks the existence of the file called test.txt in data folder on the fly during 50 seconds or so when loading the page containing the code. If file found, display "File exists" and exits the while loop. If no file found in 50 seconds, display "File does not exist" and breaks the loop too finishing loading the page.
Strange thing 1: it was not working as expected, can find the file only first time loading the page when file is there. It continues displaying "File exists" even after test.txt got removed when I refresh the page. If test.txt is not in the data folder at all, it displays "file not exists" even after I move back test.txt in the folder.
Strange thing 2: If I put a bigger file say over 170K in size, it looks working well, small files not though, especially under 40 bytes. I have tried many different ways to check file existence including absolute path, still no luck.
Thanks for any clue!
loading page...
$counter= 1;
while ($counter++) {
sleep(5);
if (file_exists("data/test.txt")) {
echo "File exists";
break;
}
if ($counter>10){
echo "File does not exist";
break;
}
}
PHP caches the results. Use clearstatcache(); before you use file_exists().
Since you are checking the existence of this file multiple times in a loop, you might need to consider caching as an issue here.
Taken from the documentation of file_Exists() -
Note: The results of this function are cached. See clearstatcache() for more details.
Perhaps you should try modifying your script to something like this -
while ($counter++) {
sleep(5);
clearstatcache();
if (file_exists("data/test.txt")) {
echo "File exists";
break;
}
...
}

PHP - Chunked file copy (via FTP) has missing bytes?

So, I'm writing a chunked file transfer script that is intended to copy files--small and large--to a remote server. It almost works fantastically (and did with a 26 byte file I tested, haha) but when I start to do larger files, I notice it isn't quite working. For example, I uploaded a 96,489,231 byte file, but the final file was 95,504,152 bytes. I tested it with a 928,670,754 byte file, and the copied file only had 927,902,792 bytes.
Has anyone else ever experienced this? I'm guessing feof() may be doing something wonky, but I have no idea how to replace it, or test that. I commented the code, for your convenience. :)
<?php
// FTP credentials
$server = CENSORED;
$username = CENSORED;
$password = CENSORED;
// Destination file (where the copied file should go)
$destination = "ftp://$username:$password#$server/ftp/final.mp4";
// The file on my server that we're copying (in chunks) to $destination.
$read = 'grr.mp4';
// If the file we're trying to copy exists...
if (file_exists($read))
{
// Set a chunk size
$chunk_size = 4194304;
// For reading through the file we want to copy to the FTP server.
$read_handle = fopen($read, 'rb');
// For appending to the destination file.
$destination_handle = fopen($destination, 'ab');
echo '<span style="font-size:20px;">';
echo 'Uploading.....';
// Loop through $read until we reach the end of the file.
while (!feof($read_handle))
{
// So Rackspace doesn't think nothing's happening.
echo PHP_EOL;
flush();
// Read a chunk of the file we're copying.
$chunk = fread($read_handle, $chunk_size);
// Write the chunk to the destination file.
fwrite($destination_handle, $chunk);
sleep(1);
}
echo 'Done!';
echo '</span>';
}
fclose($read_handle);
fclose($destination_handle);
?>
EDIT
I (may have) confirmed that the script is dying at the end somehow, and not corrupting the files. I created a simple file with each line corresponding to the line number, up to 10000, then ran my script. It stopped at line 6253. However, the script is still returning "Done!" at the end, so I can't imagine it's a timeout issue. Strange!
EDIT 2
I have confirmed that the problem exists somewhere in fwrite(). By echoing $chunk inside the loop, the complete file is returned without fail. However, the written file still does not match.
EDIT 3
It appears to work if I add sleep(1) immediately after the fwrite(). However, that makes the script take a million years to run. Is it possible that PHP's append has some inherent flaw?
EDIT 4
Alright, further isolated the problem to being an FTP problem, somehow. When I run this file copy locally, it works fine. However, when I use the file transfer protocol (line 9) the bytes are missing. This is occurring despite the binary flags the two cases of fopen(). What could possibly be causing this?
EDIT 5
I found a fix. The modified code is above--I'll post an answer on my own as soon as I'm able.
I found a fix, though I'm not sure exactly why it works. Simply sleeping after writing each chunk fixes the problem. I upped the chunk size quite a bit to speed things up. Though this is an arguably bad solution, it should work for my uses. Thanks anyway, guys!

PHP flat file download counter

I got this freely available php-script to track download statistics. Simple really, it just count downloads and pass it on to a log file and another script uses that log file to display a top 10 list. So it's exactly what I need so I would really like to make this script work. But it doesn't. Of course. I have limited knowledge in php (but have learned a lot since encountering this script!). According to the author, it has been tested on Apache- and php-versions similar to mine, without problems. So I have been hesitant to actually change any code. I have tried to chmod logfile and/or whole subdirectory to 666 and 777 with no success.
My own poor detective work leads nowhere and I have really tried. So I resort to the one thing I usually never do, to ask for help.
The link should have the form:
<a href=http://www.yoursite.com/downloader/download.php?number=1&file=filename.zip>
download.php follows below:
$number = $_GET['number'];
$file = $_GET['file'];
$logfile = "ROOT DIRECTORY PATH/logfile.txt";
$array[dir_1] = "URL PATH/DOWNLOADFILESFOLDER";
$download = "dir"."_"."$number";
if ($array[$download]) {
$fp = fopen($logfile,'r');
while (!feof($fp))
{
$data[] = chop(fgets($fp,4096));
}
fclose($fp);
$fp = fopen($logfile,"w");
if (flock($fp,LOCK_EX)) {
// list and split each filename and number of downloads
foreach ($data as $lines){
list($downloads,$filename,$realname) = split("\|",$lines);
// check if file already exists and add one more download if it does
if ($filename == $file){
$downloads++;
}
if ($filename <> ""){
fputs($fp,"$downloads|$filename|$realname\r\n");
}
}
flock($fp,LOCK_UN);
}
fclose($fp);
header("Location: $array[$download]/$file");
}
However one part of the script doesn't make sense to me; where does it obtain the filename and the realname so it can be put into the logfile if the file never has been downloaded before? The list() function and the array of the directory boggles my mind a bit. Though it seems logical.
If someone catches some fundamental error or have some tips on how I can continue, it would be highly appreciated.
PS. I am trying to track pdf-files if that helps.
UPDATE! By kind suggestion I ran error reporting and got an error. The faulty scripts had an error in it that I removed. I ran error checking again and only got "Notices" about undefined variables. I changed the error reporting to
error_reporting(E_ALL ^ E_NOTICE);
After that, no errors at all.
You have to change these:
$logfile = "ROOT DIRECTORY PATH/logfile.txt";
$array[dir_1] = "URL PATH/DOWNLOADFILESFOLDER";
To your actual paths.
Next time, turn on error reporting so you can know when stuff throw errors. One way to do this is adding the following line to the top of your script:
error_reporting(-1) // will show all errors
See: http://php.net/manual/en/function.error-reporting.php

PHP file uploading trouble

I'm having an extremely weird problem with a PHP script of mine.
I'm uploading a couple of files and having PHP put them all in one folder.
I've have trouble with random files being sent and random ones not being sent. So I debugged it and I got a very weird result from the $_FILES[] array.
I tried it with 3 files.
$_FILES["addFile"]["name"] Holds the names of the 3 files.
You'd expect $_FILES["addFile"]["tmp_name"] to hold the 3 temporary names that PHP uses to copy the files, but it doesn't. It holds just one name. The other 2 are empty strings, which generate an error whilst uploading(which I supress from being displayed)
This is very odd. I've tried mulitple situations and it just keeps on happening.
This must be something in my settings or perhaps even my code.
Here's my code:
$i = 0;
if (!empty($_FILES['addFile'])) {
foreach($_FILES['addFile'] as $addFile) {
$fileToCopy = $_FILES["addFile"]["tmp_name"][$i];
$fileName = $_FILES["addFile"]["name"][$i];
$i++;
if(!empty($fileToCopy)){
$copyTo = $baseDir."/".$fileName;
#copy($fileToCopy, $copyTo) or die("cannot copy ".$fileToCopy." to ".$copyTo);
}
}
exit(0);
}
Since the tmp_name is empty, the if-value will be false so it's gonna skip the die() function.
Does anybody know what might be causing this?
further info: I'm using Windows XP, running WAMP server. Never had this problem before and I can acces all maps from which I've tried to upload. Security settings of windows can't be the issue I think.
I'm sorry but it seams to me that you are trying to upload all 3 files with the same variable name? Is this right?
But this will not work because they will overwrite each other.
I think the better an cleaner way it would be to use something like
$i = 0;
foreach($_FILES['addFile'.$i] as $addFile) {
if(!empty($addFiles) {
move_uploaded_file($addFile['temp_name'], 'YOUR DIRECTORY');
}
$i++;
}
Relevent, but probably not going to help: but move_uploaded_file is a (slightly) better way to handle uploaded files than copy.
Are any of the files large? PHP has limits on the filesize and the time it can take to upload them ...
Better to send you here than attempt to write up what it says:
http://uk3.php.net/manual/en/features.file-upload.common-pitfalls.php
Your loop logic is incorrect. You are using a foreach loop on the file input name directly, which stores several properties that are of no interest to you ('type','size', etc).
You should get the file count from the first file and use it as the loop length:
if (!empty($_FILES['addFile']) && is_array($_FILES['addFile']['name'])) {
$length = count($_FILES['addFile']['name']);
for($i = 0; $i < $length; $i++) {
$result = move_uploaded_file($_FILES['addFile']['tmp_name'][$i],$baseDir."/" . $_FILES['addFile']['name'][$i]);
if($result === false) {
echo 'File upload failed. The following error has occurred: ' . $_FILES['addFile']['error'][$i];
}
}
}
Check the error code if you are still having problems, it should provide all the information you need to debug it.

Categories