Wordpress copy to uploads directory creates 0 bytes files - php

For some reason, this code I've been working with since the beginning seems to have stopped working on my dev environment which is set up on a free hosting service. However, it still works locally. Now, I can't recall if I've ever actually tested it on the dev environment so maybe it never worked there to begin with.
Basically, I'm using Gravity Forms to create custom posts (works just fine) and am also using multiple file uploads to add image attachments to the post. Since that's not entirely supported by GF yet I fiddled around and managed to create this little function here:
function create_post_attachment_from_gf($f, $from_url) {
//for image field, it sends content with a bunch of other parameters in a string with pipe delimiters
$split_image = explode('|', $from_url);
if( count($split_image) > 0 )
$from_url = $split_image[0];
if( !empty( $_FILES[$f]['name'] ) ) {
$file = $_FILES[$f];
$uploads = wp_upload_dir( null );
$filename = wp_unique_filename( $uploads['path'], $file['name'], null );
// Strip the query strings.
$filename = str_replace('?','-', $filename);
$filename = str_replace('&','-', $filename);
// Compute the URL
$url = $uploads['url'] . "/$filename";
$new_file = $uploads['path'] . "/$filename";
copy($from_url,$new_file);
// Move the file to the uploads dir
$stat = stat( dirname( $new_file ));
$perms = $stat['mode'] & 0000666;
# chmod( $new_file, $perms );
return array( 'file' => $new_file, 'url' => $url, 'type' => $file['type'], 'name' => $file['name'] );
}
return false;
}
And then call it this way to create the attachment:
$copied_file = create_post_attachment_from_gf('input_' . $file_uploads[$i], $entry[$file_uploads[$i]]);
$subdir = wp_upload_dir( null )["subdir"];
if( $copied_file ){
$attachment = array(
'guid' => $copied_file['url'],
'post_mime_type' => $copied_file['type'],
'post_title' => $copied_file['name'],
'post_content' => '',
'post_status' => 'inherit'
);
$attach_id = wp_insert_attachment( $attachment, $subdir . '/' .$copied_file['name'], $post_id );
$attach_data = wp_generate_attachment_metadata( $attach_id, $copied_file['file'] );
wp_update_attachment_metadata( $attach_id, $attach_data );
}
It looks like the copy is what fails here. It creates an empty file in my uploads folder with the right filename. I checked my folder permissions and even went ahead and set everything under uploads (including the gravity forms folders) to 777 and it still doesn't work for some reason.
Both my local and remote websites are running on WP 3.8.1 and all plugins are up to date on both. The databases are pretty much exactly the same aside from some test data which shouldn't interfere with this. Adding an attachment directly from the dashboard works fine. Is this something I should take up with the hosting company? Or is my code faulty? Or maybe there's a way to create an attachment without moving the file - that'd be fine with me.
Any help is appreciated.

Well, it looks like, while the copying still doesn't work remotely, I could've been uploading the image directly to the right folder from the get go.
//Have gform upload directly in the upload folder
add_filter("gform_upload_path", "change_upload_path", 10, 2);
function change_upload_path($path_info, $form_id){
$uploads = wp_upload_dir( null );
$path_info["path"] = $uploads['path'] . "/";
$path_info["url"] = $uploads['url'] . "/";
return $path_info;
}
So I removed the part that moved the file over and recreated the filename from my previous function and everything works as planned now. Can't believe I spent a few hours on this... Hopefully this helps someone else?

Related

wp_delete_attachment, wp_delete_file_from_directory and wp_delete_file() does not delete file from server

I am trying to regenerate a PDF file whenever a post is being saved/updated. The PDF file name changes according to post_meta data, therefore I want to delete the existing PDF attachment AND the file from the server when a post is saved/updated, before the pdf gets regenerated and attached.
wp_delete_attachment() deletes the attachment alright, but the file stays on the server even when forced to delete.
I also tried wp_delete_file_from_directory( $file, $path); It returns true for having deleted the file, but the file stays on the server. Same for wp_delete_file();
The only thing that seemed to be working was unlink(), but that creates another problem, because in case the file name doesn't change, unlink() seems to put a stop to creating the file with the same name.
wp_update_post( $my_post );
if(get_post_status( $post_id ) == "publish"):
$existing_PDFs = get_attached_media('application/pdf', $post_id);
foreach($existing_PDFs as $pdf):
$file = get_attached_file($pdf->ID, true);
$path = pathinfo($file, PATHINFO_DIRNAME);
wp_delete_file_from_directory( $file, $path);
wp_delete_file( $file );
wp_delete_attachment($pdf->ID, true);
endforeach;
include('generate-single-machine-pdf.php');
endif;
What's the secret to get Wordpress to delete a file from the server along with the attachment?
The solution was to conditionally use unlink after wp_delete_attachment in case the generated PDF had the same name as the deleted PDF. In that case no deletion of attachment or unlinking was needed, only to overwrite the existing file.
For updating posts:
$savePath = trailingslashit($uploads_dir).$new_file_name.'.pdf';
$pdf->Output($savePath, 'F');
$existing_PDF = get_attached_media('application/pdf', $post_id);
foreach($existing_PDF as $pdf):
$oldPDFID= $pdf->ID;
$file = get_attached_file($oldPDFID, true);
$old_file_name = pathinfo($file,PATHINFO_BASENAME);
endforeach;
}
$old_pdf = pathinfo($file,PATHINFO_BASENAME);
#######CREATE PDF ATTACHMENT####
$args = array(
'post_title' => "$new_file_name",
'post_content' => '',
'post_mime_type' => 'application/pdf',
);
$new_file_name = $new_file_name.".pdf";
//DELETE OLD ATTACHMENT
if($new_file_name != $old_file_name):
wp_delete_attachment($oldPDFID, true);
unlink($file);
endif;
$pdfID = wp_insert_attachment($args, $savePath, $post_id);

Make Wordpress wp_delete_attachment delete files from a pre-defined custom folder

We have created a custom post type which allows our client to upload files to a folder outside of the standard Wordpress uploads folder (wp-content/upload-assets). These files are to be handled seperately from the standard wp-content/uploads folder and this is why we CANNOT use
define( 'UPLOADS', 'mycustomfolder' );
in the wp-config.php.
Instead we use this to temporarily change the uploads folder to wp-content/upload-assets:
add_filter('upload_dir', 'my_upload_dir');
$uploaded_file = wp_handle_upload($_FILES['xxxx_image'], $upload_overrides);
remove_filter('upload_dir', 'my_upload_dir');
We are using this to remove all attachments from a particular post:
add_filter('upload_dir', 'my_upload_dir');
$attachments = get_posts( array(
'post_type' => 'attachment',
'posts_per_page' => -1,
'post_status' => 'any',
'post_parent' => $pid
) );
foreach ( $attachments as $attachment ) {
if ( false === wp_delete_attachment( $attachment->ID, true ) ) {
echo 'Attachment could not be deleted.';
}
}
remove_filter('upload_dir', 'my_upload_dir');
wp_delete_attachment should also delete all associated files from disk but it doesn't work because our files are in our custom folder (wp-content/upload-assets).
Here's the code for our my_upload_dir function:
function my_upload_dir($upload) {
$upload['subdir'] = '';
$upload['basedir'] = WP_CONTENT_DIR;
$upload['baseurl'] = WP_CONTENT_URL;
$upload['path'] = $upload['basedir'] . '/upload-assets';
$upload['url'] = $upload['baseurl'] . '/upload-assets';
return $upload;
}
How do we make wp_delete_attachment remove the files in our custom wp-content/upload-assets folder?
Hi You can do this way if want to delete the file, but it will not remove all post meta fields, taxonomy, comments, etc. associated with the attachment.
Hope this help
foreach ( $attachments as $attachment ) {
if ( false === wp_delete_attachment( $attachment->ID, true ) ) {
$file = get_attached_file( $attachment->ID );
$file = str_replace( "uploads", "upload-assets", $file);
wp_delete_file( $file );
}
}
I have not tested this code, but i hope it should work
Staying in the domain of current question you can use "get_attached_file" filter to directly alter the file path string used to grab the path of file to be deleted. Specifically add this function to your functions.php
function sr_update_uploads_directory( $file )
{
return str_replace( "uploads", "upload-assets", $file) // Change path to upload-assets from uploads
}
add_filter( 'get_attached_file', 'sr_update_uploads_directory' );
Don't have time for testing currently. So, please excuse me for that. Hope it helps. :)

Wordpress multisite wp_upload_dir wrong

currently i'm trying to upload a Image to a Wordpress-Multisite at server side.
(The image is already on another path at the same server)
I've written a small PHP-script which should handle this:
$upload_dir = wp_upload_dir();
var_dump( $upload_dir);
$filename = basename($imagepath);
if (wp_mkdir_p($upload_dir['path'])) {
$file = $upload_dir['path'].'/'.$filename;
} else {
$file = $upload_dir['basedir'].'/'.$filename;
}
copy($imagepath, $file);
$wp_filetype = wp_check_filetype($filename, null);
$attachment = array(
'guid' => $upload_dir['url'].'/'.basename($filename),
'post_mime_type' => $wp_filetype['type'],
'post_title' => sanitize_file_name($filename),
'post_content' => '',
'post_status' => 'inherit', );
$attach_id = wp_insert_attachment($attachment, $file, $postid);
Everything works fine, but the image is stored in the wrong folder.
wp_upload_dir(); returns the common path /wp-content/uploads/2016/03, not the path for the specific subsite, wich will be /wp-content/uploads/sites/SITE_ID/2016/03
Later when WP uses the image, the url of the image is set to http://example.com/wp-content/uploads/sites/SITE_ID/2016/03/IMAGE.JPG (which is not correct...)
Uploading a file with the built-in media-upload tool from wordpress works correct (files are stored in /wp-content/uploads/sites/SITE_ID/2016/03)
You see, wp_upload_dir() is not working correct..
Thanks..
i solved it!
For everyone with the same problem, the solution is simple:
When you're on multisite, register a filter for "upload_dir"
define a function, where you change temporarily the paths and urls
That's it!
if(is_multisite()){
add_filter('upload_dir', 'fix_upload_paths');
}
function fix_upload_paths($data)
{
$data['basedir'] = $data['basedir'].'/sites/'.get_current_blog_id();
$data['path'] = $data['basedir'].$data['subdir'];
$data['baseurl'] = $data['baseurl'].'/sites/'.get_current_blog_id();
$data['url'] = $data['baseurl'].$data['subdir'];
return $data;
}
Hope someone can use it. Hours of hours for me.
A simpler method is to use the switch_to_blog() function
if( is_multisite() ) {
switch_to_blog( get_current_blog_id() );
$imgdir = wp_upload_dir();
// do more process related to current blog
// close the swicth
restore_current_blog();
}
See details at https://developer.wordpress.org/reference/functions/switch_to_blog/

wp_redirect not working

I am trying to post to a page and do some wordpress insertion in post but somehow the redirect is not working and after that. I tried following three options:
wp_redirect($location);
wp_safe_redirect($location);
header('Location:http://example.com');
here is what I want to do:
posting to another page.
look for file to be uploaded and upload directory
Upload the file.
Set post thumbnail using set_post_thumbnail
redirect to desired page.
the script work till setting thumbnail and then dies.
If anyone want to use it to upload thumbnail from template front end, they can use it.
// if you have this in a file you will need to load "wp-load.php" to get access to WP functions. If you post to "self" with this code then WordPress is by default loaded
require $_SERVER['DOCUMENT_ROOT'] . "/wp-load.php";
// require two files that are included in the wp-admin but not on the front end. These give you access to some special functions below.
require $_SERVER['DOCUMENT_ROOT'] . "/wp-admin/includes/file.php";
require $_SERVER['DOCUMENT_ROOT'] . "/wp-admin/includes/image.php";
// required for wp_handle_upload() to upload the file
$upload_overrides = array( 'test_form' => FALSE );
global $current_user;
get_currentuserinfo();
$logged_in_user = $current_user->ID;
//get user POST information
global $post;
$loop = new WP_Query( array(
'posts_per_page' => 1,
'post_type' => "vet-profile",
'order' => "ASC",
'orderby' => "menu_order",
'author'=>"$logged_in_user"
)
);
while ( $loop->have_posts() ): $loop->the_post();
$current_postID = $post->ID;
$current_posttitle = get_the_title();
endwhile;
// count how many files were uploaded
$upload_files = $_FILES[ 'upload_files' ];
// load up a variable with the upload direcotry
$uploads = wp_upload_dir();
// foreach file uploaded do the upload
//foreach ( range( 0, $count_files ) as $i )
//{
// create an array of the $_FILES for each file
$file_array = array(
'name' => $_FILES['upload_files']['name'],
'type' => $_FILES['upload_files']['type'],
'tmp_name' => $_FILES['upload_files']['tmp_name'],
'error' => $_FILES['upload_files']['error'],
'size' => $_FILES['upload_files']['size'],
);
// check to see if the file name is not empty
if ( !empty( $file_array['name'] ) )
{ ?>
<?php
// upload the file to the server
$uploaded_file = wp_handle_upload( $upload_files, $upload_overrides );
if ( $uploaded_file )
{
echo '<script>alert("Image successfully uploaded.\n");</script>';
}
else
{
echo '<script>alert("Fish! some error occured. Please try again.");</script>';
}
// checks the file type and stores in in a variable
$wp_filetype = wp_check_filetype( basename( $uploaded_file['file'] ), null );
// set up the array of arguments for "wp_insert_post();"
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename( $uploaded_file['file'] ) ),
'post_content' => '',
'post_author' => $logged_in_user,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_parent' => $current_postID,
'guid' => $uploads['url'] . '/' . $file_array['name']
);
// insert the attachment post type and get the ID
$attachment_id = wp_insert_attachment( $attachment, $uploaded_file['file'], $current_postID );
// generate the attachment metadata
$attach_data = wp_generate_attachment_metadata( $attachment_id, $uploaded_file['file'] );
// update the attachment metadata
wp_update_attachment_metadata( $attachment_id, $attach_data);
// set thumbnail to the current post
set_post_thumbnail( $current_postID, $attachment_id );
echo '<script>alert("set thumbnail")';
$location = empty($_POST['redirect_to']) ? get_redirect_link() : $_POST['redirect_to'];
wp_safe_redirect( $location );
echo '<script>alert("End Loop");</script>';
}
Thanks in Advance
I've found that the only place I can reliably call wp_redirect is in a callback function to the init action hook (http://codex.wordpress.org/Plugin_API/Action_Reference/init) as it clearly states in the documentation:
Runs after WordPress has finished loading but before any headers are
sent. Useful for intercepting $_GET or $_POST triggers.
You might want to look into this. The other thing you might want to try, if this doesn't work for you, is using output buffering. Here's a neat tutorial on how to do that:
http://tommcfarlin.com/wp_redirect-headers-already-sent/
echo '<script>alert("set thumbnail")';
$location = empty($_POST['redirect_to']) ? get_redirect_link() : $_POST['redirect_to'];
wp_safe_redirect( $location );
echo '<script>alert("End Loop");</script>';
The above code will most surely not work. You can't redirect after you've written something to the output. I didn't check the rest of the code, but if it works as you say, removing the top and bottom row (or just the top row even) should make it all work:
$location = empty($_POST['redirect_to']) ? get_redirect_link() : $_POST['redirect_to'];
wp_safe_redirect( $location );
(If you enable debug mode in wp-config.php you should see an error message instead of just a white screen. So if this doesn't work, you can copy the error over here and we can know exactly what the problem is.)

Trying to generate WordPress thumbnails programmatically

I'm trying to add a bunch of posts programmatically, and then add their attendant images. I have an array with all the image filenames in it, and I've been able to add them to the database, but I can't seem to get the proper thumbnails created.
The posts are coming from a csv located in wp-content/uploads/dirname/. They have numbers in their filenames which correspond to an ID in the CSV, which is how I know what images need to be added to what post id.
I've gotten the wp_insert_attachment() part to work with the images right there in their own little directory, but I couldn't get the thumbnails to generate. I installed the regenerate thumbnails plugin, and it was able to generate them, but I can't seem to get it to happen programmatically.
I thought that might be because wp_generate_attachment needs the photos to be in /uploads/2011/12/ (e.g.), so I started down the path of moving the images and then trying to add them. This makes sense anyway because I kinda want to make copies rather than have 5 or 6 different media sizes added to my wp-content/uploads/dirname/ dir.
Anyway, it doesn't work. Moving the images via PHP's copy doesn't work, and the thumbnails don't generate.
foreach ($frazerfiles[$stock_num] as $stock_img){
require_once(ABSPATH . 'wp-admin/includes/image.php');
echo "... ...Trying to add attachment metadata...";
// copy the file to the upload dir
$uploads = wp_upload_dir();
$file_to_move = ABSPATH."wp-content/uploads/".$stock_img;
if (copy($file_to_move, $uploads['path']."/")) {
echo "Moved $file_to_move to ".$uploads['path']."/";
$my_moved_file = $uploads['path']."/".$stock_img;
// I think this is failing because the images aren't in the upload dir.
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename($stock_img)),
'post_content' => '',
'post_status' => 'inherit'
);
if ($attach_id = wp_insert_attachment( $attachment, $my_moved_file, $newpostid )) {
if ($attach_data = wp_generate_attachment_metadata( $attach_id, $my_moved_file)) {
echo "...success for $my_moved_file: ID:$attach_id<br />\n";
} else {
echo "...FAILED for $my_moved_file ID:$attach_id<br />\n";
print_r($attach_data);
}
} else { // inserting attachment failed
echo "Insert attachment failed for $my_moved_file to $newpostid<br />\n";
}
} else {
echo "Failed moving $file_to_move to ".$uploads['path']."/";
}
}// images foreach
After cross checking with WordPress core files, the only thing that seems to be missing out is wp_update_attachment_metadata immediately after wp_generate_attachment_metadata.
Try adding
wp_update_attachment_metadata($attach_id, $attach_data);
after
echo "...success for $my_moved_file: ID:$attach_id<br />\n";
So the if block looks like
if ($attach_data = wp_generate_attachment_metadata( $attach_id, $my_moved_file)) {
echo "...success for $my_moved_file: ID:$attach_id<br />\n";
wp_update_attachment_metadata($attach_id, $attach_data);
} else {
echo "...FAILED for $my_moved_file ID:$attach_id<br />\n";
print_r($attach_data);
}
Suggestion: (not related to the question)
move the line
require_once(ABSPATH . 'wp-admin/includes/image.php');
outside(above) the for loop.
UPDATE 1:
Adding suggestion to fix the copy issue.
You missed out the "check the file type" line.
(PHP copy function will fail if the destination file($my_moved_file) already exists)
Change this code
// copy the file to the upload dir
$uploads = wp_upload_dir();
$file_to_move = ABSPATH."wp-content/uploads/".$stock_img;
if (copy($file_to_move, $uploads['path']."/")) {
echo "Moved $file_to_move to ".$uploads['path']."/";
$my_moved_file = $uploads['path']."/".$stock_img;
// I think this is failing because the images aren't in the upload dir.
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename($stock_img)),
'post_content' => '',
'post_status' => 'inherit'
);
TO
// copy the file to the upload dir
$uploads = wp_upload_dir();
$file_to_move = ABSPATH."wp-content/uploads/".$stock_img;
$my_moved_file = $uploads['path']."/".$stock_img;
if (copy($file_to_move, $my_moved_file)) {
echo "Moved $file_to_move to ".$my_moved_file;
// Check the file type
$wp_filetype = wp_check_filetype(basename($my_moved_file), null );
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename($my_moved_file)),
'post_content' => '',
'post_status' => 'inherit'
);

Categories