Is there a WP Way of getting a filehandle?

I’m using an external CSV reading library that takes a filehandle (resource) as an argument. I’m using wp_handle_upload() to actually process and store the file in the Uploads directory, but that returns the file path, not a resource.

Is $filehandle = fopen( $file['file'], 'r' ) acceptable here, or is there a better WP alternative? I don’t see anything that fits the bill in file.php, or anywhere else I’ve looked.

Related posts

Leave a Reply

2 comments

  1. What follows is kind of complicated. You can probably just use fopen or file_get_contents without any issues.

    There’s the filesystem api. Which deals with determining ownership of a file and returning the correct way of accessing it — most of the time that just means normal PHP functions (or the direct filesystem class).

    Otto has a nice tutorial on this which I’m copied/altered to figure out how it works for this answer.

    Essentially you use request_filesystem_credentials to get the appropriate information to interact with the file system. This might be nothing (eg. direct, see the link above) or it may show a form to the user so they can enter the username/password for FTP or SSH. Depends on your server setup.

    Some quick examples. Let’s add an admin page, with a simple form.

    <?php
    add_action('admin_menu', 'wpse74395_add_menu_page');
    function wpse74395_add_menu_page()
    {
        add_options_page(
            __('Filesystem', 'wpse'),
            __('Filesystem', 'wpse'),
            'manage_options',
            'wpse-filesystem',
            'wpse74395_page_cb'
        );
    }
    
    function wpse74395_page_cb()
    {
        if(wpse74395_use_filesystem())
            return;
    
        ?>
        <div class="wrap">
            <?php screen_icon(); ?>
            <h2><?php _e('Filesystem Practice', 'wpse'); ?></h2>
            <form method="post" action="">
                <?php wp_nonce_field('wpse74395-nonce'); ?>
                <p><input name="save" type="submit" value="<?php esc_attr_e('Go!', 'wpse'); ?>" class="button-primary" /></p>
            </form>
        </div>
        <?php
    }
    

    The wpse74395_use_filesystem function:

    <?php
    function wpse74395_use_filesystem()
    {
        if(empty($_POST['save']))
            return false;
    
        // can we do this?
        check_admin_referer('wpse74395-nonce');
    
        // try to get the filesystem credentials.
        $url = wp_nonce_url(admin_url('options-general.php?page=wpse-filesystem'), 'wpse74395-nonce');
        if(false === ($creds = request_filesystem_credentials($url)))
        {
            // we didn't get creds...
            // The user will see a form at this point, so stop the
            // rest of the page.
            return true; 
        }
    
        // use WP_Filesystem to check initialize the global $wp_filesystem
        if(!WP_Filesystem($creds))
        {
            // didn't work, try again!
            request_filesystem_credentials($url);
            return true;
        }
    
        global $wp_filesystem;
    
        // get your file path
        $fp = WP_CONTENT_DIR . '/test.txt';
    
        // do your thing.
        if($wp_filesystem->exists($fp))
        {
            $res = $wp_filesystem->get_contents($fp);
            var_dump($res);
            return true;
        }
    
        // nothing worked, try again.
        return false;
    }
    

    The comments should help explain what’s going on. Essentially: make sure we’re in a POST request (form submission), and the request checks out (nonce validation). From there, we’ll try to get filesystem credentials. If we don’t get any, a form will show to collect them, so stop the rest of the page from showing.

    By only giving request_filesystem_credentials the first argument, we’re letting WP decide what method we need to use. Most of the time this is direct and the user won’t see anything. Please note that request_filesystem_credentials will do everything it can to get the stuff without asking the user — database options, config options, etc.

    Once we have the creds, try to initialize the global $wp_filesystem object with WP_Filesystem. If it works, awesome! If not, try to get the credentials again.

    If everything checks out, use the $wp_filesystem as you need to. They all have a consistent interface. Here’s the above code in a plugin.

  2. WordPress do not use fopen(). The WordPress filesystem uses four methods to access a file:

    • file_get_contents() (method direct)
    • sockets via a ftp class (method ftpsockets)
    • ftp via ftp_connect() / ftp_ssl_connect() (method ftpext)
    • ssh2 via ssh2_connect() (method ssh2)

    You have to create the filehandle on your own with fopen(). When you use wp_handle_upload(), than WordPress should have sanitized and verified the file. $file['file'] should be clean and usable.