PHP: fopen error handling - php

I do fetch a file with
$fp = fopen('uploads/Team/img/'.$team_id.'.png', "rb");
$str = stream_get_contents($fp);
fclose($fp);
and then the method gives it back as image. But when fopen() fails, because the file did not exists, it throws an error:
[{"message":"Warning: fopen(uploads\/Team\/img\/1.png): failed to open stream: No such file or directory in C:\...
This is coming back as json, obviously.
The Question is now: How can i catch the error and prevent the method from throwing this error directly to the client?

You should first test the existence of a file by file_exists().
try
{
$fileName = 'uploads/Team/img/'.$team_id.'.png';
if ( !file_exists($fileName) ) {
throw new Exception('File not found.');
}
$fp = fopen($fileName, "rb");
if ( !$fp ) {
throw new Exception('File open failed.');
}
$str = stream_get_contents($fp);
fclose($fp);
// send success JSON
} catch ( Exception $e ) {
// send error message if you can
}
or simple solution without exceptions:
$fileName = 'uploads/Team/img/'.$team_id.'.png';
if ( file_exists($fileName) && ($fp = fopen($fileName, "rb"))!==false ) {
$str = stream_get_contents($fp);
fclose($fp);
// send success JSON
}
else
{
// send error message if you can
}

You can use the file_exists() function before calling fopen().
if(file_exists('uploads/Team/img/'.$team_id.'.png')
{
$fp = fopen('uploads/Team/img/'.$team_id.'.png', "rb");
$str = stream_get_contents($fp);
fclose($fp);
}

[{"message":"Warning: fopen(uploads\/Team\/img\/1.png): failed to open stream: No such file or directory in C:\...
the error is clear: you've put the wrong directory, you can try what you whant but it'll not work. you can make it work with this:
take your file and put it in the same folder of your php file
(you'll be able to move it after don't worry, it's about your error)
or on a folder "higher" of your script (just not outside of your www
folder)
change the fopen to ('./$team_id.'png',"rb");
rerun your script file
don't forget this : you can't access a file that is'nt in your "www" folder
(he doesn't found your file because he give you her name: the name come from the $team_id variable)

Generically - This is probably the best way to do file-io in php (as mentioned by #Cendak here)
$fileName = 'uploads/Team/img/'.$team_id.'.png';
if ( file_exists($fileName) && ($fp = fopen($fileName, "rb"))!==false ){
$str = stream_get_contents($fp);
fclose($fp);
// send success JSON
}else{
// send an error message if you can
}
But it does not work with PHP 7.3, these modifications do,
if(file_exists($filename) && ($fp = fopen($filename,"r") !== false)){
$fp = fopen($filename,"r");
$filedata = fread($fp,filesize($filename));
fclose($fp);
}else{
$filedata = "default-string";
}

Related

Issue on Reading .txt inside a Zipped File by PHP [duplicate]

I need to read the content of a single file, "test.txt", inside of a zip file. The whole zip file is a very large file (2gb) and contains a lot of files (10,000,000), and as such extracting the whole thing is not a viable solution for me. How can I read a single file?
Try using the zip:// wrapper:
$handle = fopen('zip://test.zip#test.txt', 'r');
$result = '';
while (!feof($handle)) {
$result .= fread($handle, 8192);
}
fclose($handle);
echo $result;
You can use file_get_contents too:
$result = file_get_contents('zip://test.zip#test.txt');
echo $result;
Please note #Rocket-Hazmat fopen solution may cause an infinite loop if a zip file is protected with a password, since fopen will fail and feof fails to return true.
You may want to change it to
$handle = fopen('zip://file.zip#file.txt', 'r');
$result = '';
if ($handle) {
while (!feof($handle)) {
$result .= fread($handle, 8192);
}
fclose($handle);
}
echo $result;
This solves the infinite loop issue, but if your zip file is protected with a password then you may see something like
Warning: file_get_contents(zip://file.zip#file.txt): failed to open
stream: operation failed
There's a solution however
As of PHP 7.2 support for encrypted archives was added.
So you can do it this way for both file_get_contents and fopen
$options = [
'zip' => [
'password' => '1234'
]
];
$context = stream_context_create($options);
echo file_get_contents('zip://file.zip#file.txt', false, $context);
A better solution however to check if a file exists or not before reading it without worrying about encrypted archives is using ZipArchive
$zip = new ZipArchive;
if ($zip->open('file.zip') !== TRUE) {
exit('failed');
}
if ($zip->locateName('file.txt') !== false) {
echo 'File exists';
} else {
echo 'File does not exist';
}
This will work (no need to know the password)
Note: To locate a folder using locateName method you need to pass it like folder/ with a
forward slash at the end.

Open content.xml in a odt-file directly via php [duplicate]

I need to read the content of a single file, "test.txt", inside of a zip file. The whole zip file is a very large file (2gb) and contains a lot of files (10,000,000), and as such extracting the whole thing is not a viable solution for me. How can I read a single file?
Try using the zip:// wrapper:
$handle = fopen('zip://test.zip#test.txt', 'r');
$result = '';
while (!feof($handle)) {
$result .= fread($handle, 8192);
}
fclose($handle);
echo $result;
You can use file_get_contents too:
$result = file_get_contents('zip://test.zip#test.txt');
echo $result;
Please note #Rocket-Hazmat fopen solution may cause an infinite loop if a zip file is protected with a password, since fopen will fail and feof fails to return true.
You may want to change it to
$handle = fopen('zip://file.zip#file.txt', 'r');
$result = '';
if ($handle) {
while (!feof($handle)) {
$result .= fread($handle, 8192);
}
fclose($handle);
}
echo $result;
This solves the infinite loop issue, but if your zip file is protected with a password then you may see something like
Warning: file_get_contents(zip://file.zip#file.txt): failed to open
stream: operation failed
There's a solution however
As of PHP 7.2 support for encrypted archives was added.
So you can do it this way for both file_get_contents and fopen
$options = [
'zip' => [
'password' => '1234'
]
];
$context = stream_context_create($options);
echo file_get_contents('zip://file.zip#file.txt', false, $context);
A better solution however to check if a file exists or not before reading it without worrying about encrypted archives is using ZipArchive
$zip = new ZipArchive;
if ($zip->open('file.zip') !== TRUE) {
exit('failed');
}
if ($zip->locateName('file.txt') !== false) {
echo 'File exists';
} else {
echo 'File does not exist';
}
This will work (no need to know the password)
Note: To locate a folder using locateName method you need to pass it like folder/ with a
forward slash at the end.

PHP not writing to file from one source

I have an issue I can't seem to find the solution for. I am trying to write to a flat text file. I have echoed all variables out on the screen, verified permissions for the user (www-data) and just for grins set everything in the whole folder to 777 - all to no avail. Worst part is I can call on the same function from another file and it writes. I can't see to find the common thread here.....
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
if (!$Handle = fopen($File, 'w')) {
return "Cannot open file ($File)";
exit;
}/*
if(!flock($Handle, LOCK_EX | LOCK_NB)) {
echo 'Unable to obtain file lock';
exit(-1);
}*/
if (fwrite($Handle, $NewContents) === FALSE) {
return "Cannot write to file ($File)";
exit;
}else{
return $NewContents;
}
}else{
return "<p align=\"center\">There was an issue saving your settings. Please try again. If the issue persists contact your provider.</p>";
}
}
Try with...
$Handle = fopen($File, 'w');
if ($Handle === false) {
die("Cannot open file ($File)");
}
$written = fwrite($Handle, $NewContents);
if ($written === false) {
die("Invalid arguments - could not write to file ($File)");
}
if ((strlen($NewContents) > 0) && ($written < strlen($NewContents))) {
die("There was a problem writing to $File - $written chars written");
}
fclose($Handle);
echo "Wrote $written bytes to $File\n"; // or log to a file
return $NewContents;
and also check for any problems in the error log. There should be something, assuming you've enabled error logging.
You need to check for number of characters written since in PHP fwrite behaves like this:
After having problems with fwrite() returning 0 in cases where one
would fully expect a return value of false, I took a look at the
source code for php's fwrite() itself. The function will only return
false if you pass in invalid arguments. Any other error, just as a
broken pipe or closed connection, will result in a return value of
less than strlen($string), in most cases 0.
Also, note that you might be writing to a file, but to a different file that you're expecting to write. Absolute paths might help with tracking this.
The final solution I ended up using for this:
function ReplaceAreaInFile($AreaStart, $AreaEnd, $File, $ReplaceWith){
$FileContents = GetFileAsString($File);
$Section = GetAreaFromFile($AreaStart, $AreaEnd, $FileContents, TRUE);
if(isset($Section)){
$SectionTop = $AreaStart."\n";
$SectionTop .= $ReplaceWith;
$NewContents = str_replace($Section, $SectionTop, $FileContents);
return $NewContents;
}else{
return "<p align=\"center\">There was an issue saving your settings.</p>";
}
}
function WriteNewConfigToFile($File2WriteName, $ContentsForFile){
file_put_contents($File2WriteName, $ContentsForFile, LOCK_EX);
}
I did end up using absolute file paths and had to check the permissions on the files. I had to make sure the www-data user in Apache was able to write to the files and was also the user running the script.

PHP's fopen is terminally failing

Okay, I have GOT to be missing something totally rudimentary here.
I have an extremely simple use of PHP's fopen function, but for some reason, it will not open the file no matter what I do.
The odd part about this is that I use fopen in another function in the same script and it's working perfectly. I'm using the fclose in both functions. So, I know it's not a matter of a rogue file handle.
I have confirmed the file's path and the existence of the target file also.
I'm running the script at the command-line as root, so I know it's not apache that's the cause. And since I am running the script as root, I am fairly confident that permissions are not the issue.
So, what on earth am I missing here?
function get_file_list() {
$file = '/home/site/tmp/return_files_list.txt';
$fp = fopen($file, 'r') or die("Could not open file: /home/site/tmp/return_files_list.txt for reading.\n");
$files_list = array();
while($line = fgets($fp)) {
$files_list[] = $line;
}
fclose($fp);
return $files_list;
}
function num_records_in_file($filename) {
$fp = fopen( $filename, 'r' ); # or die("Could not open file: $filename\n");
$counter = 0;
if ($fp) {
while (!feof( $fp )) {
$line = fgets( $fp );
$arr = explode( '|', $line );
if (( ( $arr[0] != 'HDR' && $arr[0] != 'TRL' ) && $arr[0] != '' )) {
++$counter;
continue;
}
}
}
fclose( $fp );
return $counter;
}
As requested, here's both functions. The second function is passed an absolute path to the file. That is what I used to confirm that the file is there and that the path is correct.
Wow! Well, I figured it out.
On a whim, I decided to try trimming the file name. Apparently, it was carrying some whitespace or something at the end of the filename. So, when it tried to open the file, it couldn't due to looking for $filename +
Learn something new everyday, I guess.

File from SOAP, how to save?

I am working with a client on getting a gzip from their webservice. I am able to get a response with my following call:
$response = $client->call('branchzipdata', $param);
$filename = "test.gzip";
if (!$handle = fopen($filename, 'a')) {
echo "Cannot open file ($filename)";
exit;
}
if (fwrite($handle, $response) === FALSE) {
echo "Cannot write to file ($filename)";
exit;
}
Now when I attempt to write that a file, such as 'test.gzip', I am unable to open it afterwards... most likely because I am doing something horrible wrong. Any insight would be appreciated.
EDIT:
For some reason I was saving the file as '.gzip' instead of '.gz'... So in order to have it work I now have:
$response = $client->call('call', $param);
$content = base64_decode($response);
$filename = "output_zip.gz";
if (!$handle = fopen($filename, 'w')) {
echo "Cannot open file ($filename)";
exit;
}
if (fwrite($handle, $content) === FALSE) {
echo "Cannot write to file ($filename)";
exit;
}
fclose($handle);
echo system("gzip -d $filename");
(Edited based on the comments)
If the return value is base64-encoded, you need to base64-decode it before you write it to the file. Alternatively you could write it out to a file which you then base64-decode to another file before trying to open it, but that seems a bit pointless compared with just decoding it when you first get it.

Categories