4

Background

I'm developing a plugin for WordPress. I initially used file_get_contents() for two purposes:

  1. A remote file (which I changed to wp_remote_post())
  2. A local file in the plugin dir (what this question is about)

WordPress staff told me to NOT use file_get_contents() for remote _POST requests (usage 1. above), but to use wp_remost_post() instead.

From their email concerning usage 1. (above):

Using file_get_contents on remote files

Many hosts block the use of file_get_contents on remote content. This is a security measure that we fully endorse.

Thankfully, WordPress comes with an extensive HTTP API that can be used instead. It’s fast and more extensive than most home-grown alternatives. It’ll fall back to curl if it has to, but it’ll use a lot of WordPress’ native functionality first.

So, I did. But...

Solving usage 1. A remote file (above) got me to reading and thinking about a better tool for usage 2. A local file (above)

In the WordPress HTTP API docs, there is no alternative for file_get_contents() on local files, nothing like wp_file_get_contents().

(I understand this may seem strange since local files of a plugin are often static, but I am writing extra files to save cost, and I politely don't want to open that discussion. Besides, this approved plugin from someone else, code here, uses file_get_contents(), thus proving my own need is legitimate, but it doesn't prove that file_get_contents() is 'proper' WordPress-practice.)

From this blog post, clearly this was a big discussion for file_get_contents() for remote files. But, I don't see much on the web about a WordPress function for local files. From the post:

Like many others I’ve used the native PHP function file_get_contents() to receive the content from a remote file because the functions is very easy to use. But is it the best way to do that? I see many scripts using that function and even WordPress plugins are using this function while WordPress has a native function to receive remote content.

...I want to take that discussion to local files and build this plugin right.

My code (current and attempted)

I simply need to confirm whether a local file in the plugin directory exists, then confirm whether it contains a certain string. I thought it best to use file_get_contents() for local files in PHP from this question on SE. But, this is WordPress. Currently, I am using:

if ( ( ! $wp_filesystem->exists ( $check_this_file ) )
 || (strpos ( file_get_contents ( $check_this_file ),
    $check_this_string ) === false ) )

I tried using WP_Filesystem_Direct::get_contents instead:

if ( ( ! $wp_filesystem->exists ( $check_this_file ) )
 || (strpos ( WP_Filesystem_Direct::get_contents ( $check_this_file ),
    $check_this_string ) === false ) )

...but I got this error:

Deprecated: Non-static method WP_Filesystem_Direct::get_contents() should not be called statically

What should I do?

I'm not sure because there isn't even a #get-contents tag on WP.SE at the time of asking, but the function exists both in the framework and in the docs.

I want to know the "WordPress way" for plugins to read a plugin file's contents for a string test:

  • file_get_contents() (what I have now)
  • WP_Filesystem_Direct::get_contents() (but how do I make it work without the error?)
  • or some proper-reliable usage of wp_filesystem() or similar
1
  • 1
    Well, you should use $wp_filesystem->get_contents(), and that method simply calls the native PHP's file_get_contents(), so you may use it directly in your code - for reading local files/resources.
    – Sally CJ
    Commented Mar 29, 2020 at 11:02

3 Answers 3

3

The alternate of using file_get_contents() is to initiate WP_Filesystem and use its $wp_filesystem->get_contents method.

Here is a clean example method on how to use it

Example

<?php
     /**
     * This method gets a list of the most popular Google web fonts. 
     * Initialize the WP filesystem and no more using file_put_contents function
     *
     * @see     wp_filesystem()
     * @see     get_parent_theme_file_path()
     * @return  array   A list of Google web fonts
     */
    function mm_get_google_fonts() {
 
    // Call globals
    global $wp_filesystem;

    // You have to require following file in the front-end only. In the back-end; its already included
    require_once ( ABSPATH . '/wp-admin/includes/file.php' );

    // Initiate
    WP_Filesystem();
     
    $local_file =   get_parent_theme_file_path( '/assets/json/google-web-fonts.json' );
    $content    =   '';
 
    if ( $wp_filesystem->exists( $local_file ) ) {

        // following is alternate to
        // $content = json_decode( file_get_contents( $local_file ) );

        $content = json_decode( $wp_filesystem->get_contents( $local_file ) );

    } // End If Statement
 
    return $content;
 
} 
?>

For more information you can visit the official documenation of WP_Filesystem

2

$wp_filesystem->get_contents is wrong for this purpose, since you can't know what filesystem path the file is going to be accessible at using WP_Filesystem . If the user has WP_Filesystem using chrooted FTP or SFTP to the WP install dir, the server path /path/to/site/wp will need to actually be /site/wp in order for WP_Filesystem to find the file. But if you're not chrooted, it's at /path/to/site/wp

To reliably read your file you need to instantiate WP_Filesystem_Direct and then use that.

$wpfsd = new WP_Filesystem_Direct( false );
$wpfsd->get_contents ( $check_this_file )
1
  • It seems you're saying that WP_Filesystem won't follow symlinks to the place where the web user has access. So WP_Filesystem_Direct is more reliable. This is very insightful!
    – Jesse
    Commented Jan 8, 2023 at 23:52
0

$wp_filesystem->get_contents()

$wp_filesystem->get_contents() replaced file_get_contents() perfectly as a drop-in replacement. Of course, it must be initiated with WP_Filesystem(); first.

Here is a before and after example...

Before:

if ( (strpos ( file_get_contents ( $check_this_file ),
    $check_this_string ) === false) ) {...}

After:

WP_Filesystem();
if ( (strpos ( $wp_filesystem->get_contents ( $check_this_file ),
    $check_this_string ) === false) ) {...}
1
  • 2023 update: another answer recommends WP_Filesystem_Direct instead of WP_Filesystem for more reliability.
    – Jesse
    Commented Jan 8, 2023 at 23:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.