Php file get contents fatal error

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP 8 — Fatal error «Path cannot be empty» — file_get_contents(») at /inc/Engine/Optimization/AbstractOptimization.php #3422

PHP 8 — Fatal error «Path cannot be empty» — file_get_contents(») at /inc/Engine/Optimization/AbstractOptimization.php #3422

effort: [XS] < 1 day of estimated development time module: file optimization PHP8 priority: high Issues which should be resolved as quickly as possible type: bug Indicates an unexpected problem or unintended behavior

Comments

Before submitting an issue please check that you’ve completed the following steps:

  • Made sure you’re on the latest version ✅
  • Used the search feature to ensure that the bug hasn’t been reported before ✅

Describe the bug
In PHP 8, trying to get the content of a path that doesn’t exist throws a fatal error.
It is happening when we pass an empty path here for example:
https://github.com/wp-media/wp-rocket/blob/master/inc/Engine/Optimization/AbstractOptimization.php#L199

#0 /opt/httpd/htdocs/wp-admin/includes/class-wp-filesystem-direct.php(39): file_get_contents('') #1 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AbstractOptimization.php(199): WP_Filesystem_Direct->get_contents(false) #2 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php(296): WP_Rocket\\Engine\\Optimization\\AbstractOptimization->get_file_content(false) #3 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php(217): WP_Rocket\\Engine\\Optimization\\Minify\\CSS\\Combine->get_content('/opt/httpd/htdo. ') #4 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php(73): WP_Rocket\\Engine\\Optimization\\Minify\\CSS\\Combine->combine() #5 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Subscriber.php(53): WP_Rocket\\Engine\\Optimization\\Minify\\CSS\\Combine->optimize('. ') #6 /opt/httpd/htdocs/wp-includes/class-wp-hook.php(287): WP_Rocket\\Engine\\Optimization\\Minify\\CSS\\Subscriber->process('. ') #7 /opt/httpd/htdocs/wp-includes/plugin.php(212): WP_Hook->apply_filters('. ', Array)\n #8 /opt/httpd/htdocs/wp-content/plugins/wp-rocket/inc/classes/Buffer/class-optimization.php(104): apply_filters('rocket_buffer', '. ') #9 [internal function]: WP_Rocket\\Buffer\\Optimization->maybe_process_buffer('. ', 9)\n #10 /opt/httpd/htdocs/wp-includes/functions.php(4755): ob_end_flush() #11 /opt/httpd/htdocs/wp-includes/class-wp-hook.php(287): wp_ob_end_flush_all('') #12 /opt/httpd/htdocs/wp-includes/class-wp-hook.php(311): WP_Hook->apply_filters(NULL, Array) #13 /opt/httpd/htdocs/wp-includes/plugin.php(484):!WP_Hook->do_action(Array) #14 /opt/httpd/htdocs/wp-includes/load.php(1052): do_action('shutdown') #15 [internal function]: shutdown_action_hook() #16 thrown in /opt/httpd/htdocs/wp-admin/includes/class-wp-filesystem-direct.php on line 39

To Reproduce
Steps to reproduce the behavior:

  1. On a server running PHP 8 and WP Rocket
  2. Pass a path that doesn’t exist here:
  3. It will fail on line 199 with this error: https://snippi.com/s/ql270c6

Expected behavior
Per Remy’s comment here,

We can guard against it by adding an additional check, to prevent trying to get the content of a path that doesn’t exist

Backlog Grooming (for WP Media dev team use only)

  • Reproduce the problem
  • Identify the root cause
  • Scope a solution
  • Estimate the effort

The text was updated successfully, but these errors were encountered:

Источник

file_get_contents => PHP Fatal error: Allowed memory exhausted

Firstly you should understand that when using file_get_contents you’re fetching the entire string of data into a variable, that variable is stored in the hosts memory.

If that string is greater than the size dedicated to the PHP process then PHP will halt and display the error message above.

The way around this to open the file as a pointer, and then take a chunk at a time. This way if you had a 500MB file you can read the first 1MB of data, do what you will with it, delete that 1MB from the system’s memory and replace it with the next MB. This allows you to manage how much data you’re putting in the memory.

An example if this can be seen below, I will create a function that acts like node.js

function file_get_contents_chunked($file,$chunk_size,$callback) < try < $handle = fopen($file, "r"); $i = 0; while (!feof($handle)) < call_user_func_array($callback,array(fread($handle,$chunk_size),&$handle,$i)); $i++; >fclose($handle); > catch(Exception $e) < trigger_error("file_get_contents_chunked::" . $e->getMessage(),E_USER_NOTICE); return false; > return true; > 
$success = file_get_contents_chunked("my/large/file",4096,function($chunk,&$handle,$iteration) < /* * Do what you will with the here * is passed in case you want to seek ** to different parts of the file * is the section of the file that has been read so * ($i * 4096) is your current offset within the file. */ >); if(!$success) < //It Failed >

One of the problems you will find is that you’re trying to perform regex several times on an extremely large chunk of data. Not only that but your regex is built for matching the entire file.

With the above method your regex could become useless as you may only be matching a half set of data. What you should do is revert to the native string functions such as

for matching the strings, I have added support in the callback so that the handle and current iteration are passed. This will allow you to work with the file directly within your callback, allowing you to use functions like fseek , ftruncate and fwrite for instance.

The way you’re building your string manipulation is not efficient whatsoever, and using the proposed method above is by far a much better way.

Solution 2

A pretty ugly solution to adjust your memory limit depending on file size:

$filename = "yourfile.txt"; ini_set ('memory_limit', filesize ($filename) + 4000000); $contents = file_get_contents ($filename); 

The right solutuion would be to think if you can process the file in smaller chunks, or use command line tools from PHP.

If your file is line-based you can also use fgets to process it line-by-line.

Источник

Handling I/O errors in PHP

This blog post is all about how to handle errors from the PHP file_get_contents function, and others which work like it.

The file_get_contents function will read the contents of a file into a string . For example:

You can try this out on the command-line like so:

$ echo "hello" > hello.txt $ php test.php hello 

This function is widely used, but I’ve observed that error handling around it is often not quite right. I’ve fixed a few bugs involving incorrect I/O error handling recently, so here are my thoughts on how it should be done.

How file_get_contents fails

For legacy reasons, this function does not throw an exception when something goes wrong. Instead, it will both log a warning, and return false .

Which looks like this when you run it:

$ php test.php PHP Warning: file_get_contents(not-a-real-file.txt): failed to open stream: No such file or directory in test.php on line 3 PHP Stack trace: PHP 1. () test.php:0 PHP 2. file_get_contents() test.php:3 

Warnings are not very useful on their own, because the code will continue on without the correct data.

Error handling in four steps

If anything goes wrong when you are reading a file, your code should be throwing some type of Exception which describes the problem. This allows developers to put a try <> catch <> around it, and avoids nasty surprises where invalid data is used later.

Step 1: Detect that the file was not read

Any call to file_get_contents should be immediately followed by a check for that false return value. This is how you know that there is a problem.

This now gives both a warning and an uncaught exception:

$ php test.php PHP Warning: file_get_contents(not-a-real-file.txt): failed to open stream: No such file or directory in test.php on line 3 PHP Stack trace: PHP 1. () test.php:0 PHP 2. file_get_contents() test.php:3 PHP Fatal error: Uncaught Exception: File was not loaded in test.php:5 Stack trace: #0 thrown in test.php on line 5 

Step 2: Suppress the warning

Warnings are usually harmless, but there are several good reasons to suppress them:

  • It ensures that you are not depending on a global error handler (or the absence of one) for correct behaviour.
  • The warning might appear in the middle of the output, depending on php.ini .
  • Warnings can produce a lot of noise in the logs

Use @ to silence any warnings from a function call.

The output is now only the uncaught Exception :

$ php test.php PHP Fatal error: Uncaught Exception: File was not loaded in test.php:5 Stack trace: #0 thrown in test.php on line 5 

Step 3: Get the reason for the failure

Unfortunately, we lost the “No such file or directory” message, which is pretty important information, which should go in the Exception . This information is retrieved from the old-style error_get_last method.

This function might just return empty data, so you should check that everything is set and non-empty before you try to use it.

This now embeds the failure reason directly in the message.

$ php test.php PHP Fatal error: Uncaught Exception: File 'not-a-real-file.txt' was not loaded. file_get_contents(not-a-real-file.txt): failed to open stream: No such file or directory in test.php:9 Stack trace: #0 thrown in test.php on line 9 

Step 4: Add a fallback

The last time I introduced error_clear_last() / get_last_error() into a code-base, I learned out that HHVM does not have these functions.

Call to undefined function error_clear_last() 

The fix for this is to write some wrapper code, to verify that each function exists.

 echo $text; /** * Call error_clear_last() if it exists. This is dependent on which PHP runtime is used. */ function clearLastError() < if (function_exists('error_clear_last')) < error_clear_last(); >> /** * Retrieve the message from error_get_last() if possible. This is very useful for debugging, but it will not * always exist or return anything useful. */ function getLastErrorOrDefault(string $default) < if (function_exists('error_clear_last')) < $e = error_get_last(); if (isset($e) && isset($e['message']) && $e['message'] != "") < return $e['message']; >> return $default; > 

This does the same thing as before, but without breaking other PHP runtimes.

$ php test.php PHP Fatal error: Uncaught Exception: Could not retrieve image data from 'not-a-real-file'. file_get_contents(not-a-real-file): failed to open stream: No such file or directory in test.php:7 Stack trace: #0 thrown in test.php on line 7 

Since HHVM is dropping support for PHP, I expect that this last step will soon become unnecessary.

How not to handle errors

Some applications put a series of checks before each I/O operation, and then simply perform the operation with no error checking. An example of this would be:

 if(!is_file($filename)) < throw new Exception("$filename is not a file"); >if(!is_readable($filename)) < throw new Exception("$filename cannot be read"); >// Assume that nothing can possibly go wrong.. $text = @file_get_contents($filename); echo $text; 

You could probably make a reasonable-sounding argument that checks are a good idea, but I consider them to be misguided:

  • If you skip any actual error handling, then your code is going to fail in more surprising ways when you encounter an I/O problem that could not be detected.
  • If you do perform correct error handling as well, then the extra checks add nothing other than more branches to test.

Lastly, beware of false positives. For example, the above snippet will reject HTTP URL’s, which are perfectly valid for file_get_contents .

Conclusion

Most PHP code now uses try / catch / finally blocks to handle problems, but the ecosystem really values backwards compatibility, so existing functions are rarely changed.

The style of error reporting used in these I/O functions is by now a legacy quirk, and should be wrapped to consistently throw a useful Exception .

One Reply to “Handling I/O errors in PHP”

you can use this library which is a wrapper aroud all php functions :
https://github.com/thecodingmachine/safe

Leave a Reply

Recent Posts

Источник

Читайте также:  Задать блоку класс css
Оцените статью