• Resolved odp123

    (@odp123)


    Hey folks,

    I am writing a rather extensive alteration of the user profile page. Among the alterations I need users to be able to upload a pdf file.

    What I need help with is how to actually handle the pdf file, so it gets uploaded preferable with username_ prepended to filename (bob_specs.pdf)

    What I have so far:

    ///////////// PDF upload //////////////////
    
    add_action( 'show_user_profile', 'pdf_upload' );
    add_action( 'edit_user_profile', 'pdf_upload' );
    
    function pdf_upload( $user ) { ?>
    
    <table class="form-table">
    <h3>Upload PDF specifications</h3>
    <span>tutorial</span>
    <tr>
    <th><label for="pdf">PDF</label></th>
    
    <td>
    <input type="file" name="pdf" id="pdf" value="<?php echo esc_attr( get_the_author_meta( 'pdf', $user->ID ) ); ?>" class="regular-text" /><input type='button' class="upl button-primary" value="Upload PDF" id="uploadpdf"/><br />
    <span class="description">Please choose a PDF file to upload</span>
    </td>
    </tr>
    
    </table>
    <?php }
    
    ///////////// PDF upload END //////////////////

    This only adds the upload form to the profile page. So I am missing the actual handling of the file.

    after successful upload I call this in my author.php file

    <?php $user = (get_query_var('author_name')) ? get_user_by('slug', get_query_var('author_name')) : get_userdata(get_query_var('author')); ?>
    ....
    <?php echo $user->pdf; ?>
    ....

    Any inputs, advice, or code examples would be greatly appreciated.

    PS. not looking for plugins

Viewing 10 replies - 1 through 10 (of 10 total)
  • Moderator bcworkz

    (@bcworkz)

    When a user submits the form, the file is uploaded to a temp folder. you need to use move_uploaded_file() to place the file in a more permanent location. Renaming the file may be part of this process. There are several checks you must do to ensure a proper file is being uploaded and not something malicious, including checking the file content for a PDF signature. If you search about you should find examples of things to do along with specific code.

    Thread Starter odp123

    (@odp123)

    Thanks for your reply, but I think you misunderstand my objective. Writing a php function to upload a file is not a problem and tons of resources are available online for that sort of thing.

    What I am looking for is a way of doing this using wordpress’ filesystem.

    ie. wp_handle_upload which is described to “Handle PHP uploads in WordPress, sanitizing file names, checking extensions for mime type, and moving the file to the appropriate directory within the uploads directory.”

    Moderator bcworkz

    (@bcworkz)

    Yes I did misunderstand, sorry.

    You can use wp_handle_upload(). All it really does is the same things that are so well documented on tons of resources available online ?? It is nice that it’s all rolled up into one function. There are a couple quirks, which I guess is what you’re really after. One is your upload form needs a field (hidden most likely) named “action” that has a value of “wp_handle_upload”. If this is a problem because of the form already having such a field with a different value, the check can be overridden.

    The main thing is the function only verifies certain image files for validity. For PDFs you need to filter ‘wp_check_filetype_and_ext’ and do your own checks.

    Thread Starter odp123

    (@odp123)

    I might be a little inn over my head here. ‘wp_check_filetype_and_ext’ is said to only support validating images known to getimagesize(). I have found some hacks that explains how to run the file through imageMagick and all of the sudden I feel a little overwhelmed. How and what do I do with ‘wp_check_filetype_and_ext’?

    Lets work from here:

    ///////////// PDF upload //////////////////
    
    add_action( 'show_user_profile', 'pdf_upload' );
    add_action( 'edit_user_profile', 'pdf_upload' );
    
    function pdf_upload( $user ) { ?>
    
    <table class="form-table">
    <h3>Upload PDF specifications</h3>
    <span>tutorial</span>
    <tr>
    <th><label for="pdf">PDF</label></th>
    
    <td>
    <input type="file" name="pdf" id="pdf" value="<?php echo esc_attr( get_the_author_meta( 'pdf', $user->ID ) ); ?>" class="regular-text" />
    
    <input type="hidden" name="hiddenPdf" id="hiddenPdf" value="<?php upload_pdf(); ?>" class="regular-text" />
    
    <input type='button' class="upl button-primary" value="Upload PDF" id="uploadpdf"/><br />
    <span class="description">Please choose a PDF file to upload</span>
    </td>
    </tr>
    
    </table>
    <?php }
    
    function upload_pdf() {
    if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );
    $uploadedfile = $_FILES['pdf'];
    $upload_overrides = array( 'test_form' => false );
    $movefile = wp_handle_upload( $uploadedfile, $upload_overrides );
    if ( $movefile ) {
        echo "File is valid, and was successfully uploaded.\n";
        var_dump( $movefile);
    } else {
        echo "Possible file upload attack!\n";
    }
    }
    
    ///////////// PDF upload END //////////////////
    Moderator bcworkz

    (@bcworkz)

    Filter hooks go on either a plugin file or your theme’s functions.php. Your added filter callback is called by the wp_check_filetype_and_ext() function, which is in turn called by wp_handle_upload() A basic filter hook looks like this:

    add_filter('wp_check_filetype_and_ext', 'odp_check_pdf', 10, 4);
    function odp_check_pdf( $data, $file, $filename, $mimes ){
       //do the checks
       //$data is structured as array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename )
       return $data;
    }

    All the image checking done by wp_check_filetype_and_ext() is skipped over because your file is not an image. Keep in mind though that all files, not just PDFs, will pass through your callback, so the first thing to do is return immediately if $data['ext']!='pdf'. The two things that are checked for you before your callback is the filetype was checked as allowable and that the file actually exists. All else is on you.

    I’m not sure what one can do to verify the file is a true PDF. I’m fairly sure there is some sort of identifying byte sequence signature in the file. You should get enough of the file contents to verify this. That may be all you can do. But if there are other checks you can do, you should. File uploads are a major vector for hacking websites, the more thoroughly you can verify the file is a true PDF the better.

    Thread Starter odp123

    (@odp123)

    So lets say, I have added the filter, and added some kind of check what do I do with the return data. The upload_pdf function by itself called as the form action displays:
    string(212) "File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini." } " class="regular-text" />

    And Im thinking that the function will only get executed when the form is submitted?

    I really appreciate the time you are taking to help me out, but would you be kind to ellaborate on the code i got?

    ///////////// PDF upload //////////////////
    
    add_action( 'show_user_profile', 'pdf_upload' );
    add_action( 'edit_user_profile', 'pdf_upload' );
    
    function pdf_upload( $user ) { ?>
    
    <table class="form-table">
    <h3>Upload PDF specifications</h3>
    <span>tutorial</span>
    <tr>
    <th><label for="pdf">PDF</label></th>
    
    <td>
    <form action="<?php odp_check_pdf(); ?>" method="post" enctype="multipart/form-data">
    <input type="file" name="pdf" id="pdf" value="<?php echo esc_attr( get_the_author_meta( 'pdf', $user->ID ) ); ?>" class="regular-text" />
    
    <input type="hidden" name="hiddenPdf" id="hiddenPdf" value="<?php upload_pdf(); ?>" class="regular-text" />
    
    <input type='submit' class="upl button-primary" value="Upload PDF" id="uploadpdf"/><br />
    <span class="description">Please choose a PDF file to upload</span>
    </form>
    </td>
    </tr>
    
    </table>
    <?php }
    
    add_filter('wp_check_filetype_and_ext', 'odp_check_pdf', 10, 4);
    function odp_check_pdf( $data, $file, $filename, $mimes ){
       //do the checks
       //$data is structured as array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename )
        if ($data['ext']!='pdf') {
        echo 'nope';
        }
       return $data;
    }
    
    function upload_pdf() {
    if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );
    $uploadedfile = $_FILES['pdf'];
    $upload_overrides = array( 'test_form' => false );
    $movefile = wp_handle_upload( $uploadedfile, $upload_overrides );
    if ( $movefile ) {
        echo "File is valid, and was successfully uploaded.\n";
        var_dump( $movefile);
    } else {
        echo "Possible file upload attack!\n";
    }
    }
    
    ///////////// PDF upload END //////////////////
    Moderator bcworkz

    (@bcworkz)

    The way your form is setup now, no function is executed.

    As long as you’re using the user profile hooks, you cannot define your own form because the output is already inside a form. You need to revert to what you had originally where only form fields were output. In order to handle your portion of the form submit, hook something like ‘profile_update’ to run upload_pdf().

    Then the file content should be in the temp directory and $_FILES is properly populated, and wp_handle_upload() should work. Provided wp_check_filetype_and_ext() is properly overridden. When your callback is called, $data['proper_filename'] is set to false. Returning this indicates a failure to wp_handle_upload(). Even if you plan to implement a better check later, for the function to return the correct value, you should for the interim do something like this:

    if ($data['ext']!='pdf') {
        $data['proper_filename'] = $filename;
     }

    I’m not sure what you want me to elaborate on, but other than what I’ve mentioned, it looks basically correct. I may have missed something though. The ultimate test is if it works without throwing any errors, warnings, or notices. Even though simple in concept, getting all the parts to work properly can be a challenge. For every failure, you need to use debugging techniques to determine why, then fix the problem. Each time through, the code will get farther along until eventually everything works.

    Thread Starter odp123

    (@odp123)

    Ahh but this is absolutely perfect.

    I hooked up the uploaded file to update_user_meta and now have an array in the db with the filename.

    In my author.php I hooked up the file like this, but while it works now, I am not sure if it will work when the month change.

    <?php $upload_dir = wp_upload_dir();?> <p><b>PDF: </b><?php echo $upload_dir[‘url’].’/’.$user_id->pdf[‘name’]; ?></p>

    would it not be smarter to somehow have the absolute filepath saved with the name or something?

    Thread Starter odp123

    (@odp123)

    HAHAHA never mind I just return $movefile[‘url’] to update_user_meta.

    Thanks a bunch bcworkz, learned a lot from this experience

    Moderator bcworkz

    (@bcworkz)

    You’re welcome!
    It’s awesome it all works, file handling can sometimes be very frustrating just because some stupid detail was overlooked.

Viewing 10 replies - 1 through 10 (of 10 total)
  • The topic ‘pdf upload on user profile page’ is closed to new replies.