I'm having some trouble with deleting a file from a website using PHP.
I have some code which uploads a file, (which works) it then resizes, renames, changes image format and saves the uploaded image twice. (Once as the full size image, once as a thumbnail.)
This part works fine, no worries.
However, I'm writing some error checking code that will delete these uploaded images if the image formats do not match the files extension.
(For example, create a bmp file in mspaint and save it. close paint, reopen the bmp file in paint then click file, save as, then save it as a png.
What happens is paint will just change the extension and not the file format. Try opening that png with my php script and it will fail with an 'image not a valid png' error.
I have written a custom error function to inform the user that the image format is bad. (Because informing users why they have an issue is better than just telling them they have an issue.)
The below code will display the name of the file, which does exist, but will not pass the 'file_exists' check.
print( $imagename . ".jpg<br/>\n" ); // Displays 'images/filename.jpg'
if ( file_exists( $imagename.".jpg" ) ) { unlink( $imagename.".jpg" ); print( "Image deleted<br/>\n" ); }
I've tried pre-pending a "/", with no luck, and I'm not really sure why the file isn't being found?
Any hints? (And apologies for the huge block of text!)
Try adding this to your script:
print( getcwd() .'/'. $imagename . ".jpg<br/>\n" ); // Displays full path
This will tell you where PHP is looking for the file to delete. If it's different to where the file actually resides, then you need to give PHP the right path. There are lots of ways to achieve this, two basic examples are.
Use an absolute path: (works until you move your code)
$rootPath='/var/www/html/orsimilar/';
if ( file_exists( $rootPath. $imagename.".jpg" ) ) { unlink( $imagename.".jpg" ); print( "Image deleted<br/>\n" ); }
Or use a relative one:
$rootPath=__DIR__ . '/../pathtoimages';
if ( file_exists( $rootPath. $imagename.".jpg" ) ) { unlink( $imagename.".jpg" ); print( "Image deleted<br/>\n" ); }
Thanks everyone for your help.
Using getcwd() confirmed that it was looking in the correct location for the file, however the issue was on my part.
My code created the new blank image, then copies the source image to it, (which is the part it would fail at) then if there was a failure, it would then copy the blank images to the final location. At the point of failure, the files do not in fact exist for file_exists to find them"
I've now checked for failure and will not copy the file if there was an issue.
Again, thanks for your help but once again, PEBCAK!
Related
I am attempting to write a plugin that, upon activation, programmatically does everything that is needed to upload an image to the uploads directory. In other words: it does everything that would happen if you manually did the drag-and-drop of the image on the Add New Media Library Screen:
Details:
I am not submitting a POST request. I am simply trying to find out what functions I need to call in order to do the following (which wordpress does in the drag-and-drop Media Library screen:
Find and grab the image specified by the FULL path (example: image is located on the desktop. It is NOT in the uploads directory).
Upload that image, as well as various versions of that image, in the uploads directory
create a post of post_type equal to attachment
create relevant postmeta records
Example:
It seems like wp_insert_attachment simply cannot do this because the image MUST already exist in the uploads directory.
# Below is a comment from the wp_insert_attachment example:
// $filename should be the path to a file in the upload directory
This post just says this isn't possible with wp_insert_attachment but does not provide a solution.
Question(s):
How can I programmatically upload an attachment whose path does not exist in the wp-content/uploads directory? Instead, for example: the full path to the image is located on the desktop.
Is this simply impossible to do without doing it in the context of uploading the image via a form and POST request? Ideally I want to call some function that says "Here is the full path to the image which is located on the desktop. Now: do all the work necessary to upload the image within the context of my wordpress project."
Thanks!
I saw you were referencing your server's desktop. Make sure that the files you are trying to load are accessible by the WordPress App User!
If you have to do this programmatically, it looks like media_handle_sideload might do the trick. Same functionality as media_handle_upload, but I don't think it requires the POST request to activate it like media_handle_upload does.
So
Step 1: Move files to location accessible by the WordPress application (like wp-content/uploads)
Step 2: grab url for the file you need to "upload" (something like host/wp-content/uploads/image.jpg)
Step 3: Figure out the post Id you need to reference for the image, and use media_handle_sideload to validate and store the file (code snippet below from the Wordpress Codex)
<?php
// Need to require these files
if ( !function_exists('media_handle_upload') ) {
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
}
$url = "http://s.wordpress.org/style/images/wp3-logo.png";
$tmp = download_url( $url );
if( is_wp_error( $tmp ) ){
// download failed, handle error
}
$post_id = 0;
$desc = "The WordPress Logo";
$file_array = array();
// Set variables for storage
// fix file filename for query strings
preg_match('/[^\?]+\.(jpg|jpe|jpeg|gif|png)/i', $url, $matches);
$file_array['name'] = basename($matches[0]);
$file_array['tmp_name'] = $tmp;
// If error storing temporarily, unlink
if ( is_wp_error( $tmp ) ) {
#unlink($file_array['tmp_name']);
$file_array['tmp_name'] = '';
}
// do the validation and storage stuff
$id = media_handle_sideload( $file_array, $post_id, $desc );
// If error storing permanently, unlink
if ( is_wp_error($id) ) {
#unlink($file_array['tmp_name']);
return $id;
}
$src = wp_get_attachment_url( $id );
?>
If you have the file already on the server, but it doesn't have a path setup in wordpress yet (i.e. you can't browse to it from a web browser), there's a plugin called "Add from Server" where it opens a miniature file browser window that's connected to your server, and then it creates the database records in your WordPress instance to the files residing on the server, so that you can pull them up in the media browser on wp-admin.
Warning though, this plugin is a security risk since the plugin essentially gains file-access to your webserver's directory. If you have to, say, bulk upload a bunch of files to WordPress and they're already on the server, I would install the plugin, create the database records for the files, and then immediately deactivate and uninstall the plugin!
You are looking for media_handle_upload. You can then use wp_update_attachment_metadata.
Here is a basic version:
<?php
// Use 0 as your post ID if you don't want to attach it to any post
$image = media_handle_upload($file, $post_id);
wp_update_attachment_metadata( $image, $data );
?>
You can see a more advanced version using a frontend form here.
You could alternatively use media_handle_sideload if uploading an image from a URL.
I have a directory called resale_certificates where I save files to but encrypt the name using parts of their email and codes assigned to them.
NOTE: The encryption is the same every time but unique to each user!
When they upload image.png it will save the file to theirEncrypt.png
If they upload another image.png it will replace theirEncrypt.png
However when they upload image.jpg now there will be theirEncrypt.jpg and theirEncrypt.png in the resale_certificates directory.
What is the best way to handle this? I'm looking for advice and open to changing how I'm saving it or tricks I could do to prevent this!
Thank You!
Well, you could use an image library to transform their uploaded image to whatever format you want, i.e. if they upload a .JPG you can use image libraries like Imagick or GD to output a .PNG file and upload those.
However, if you don't mind either the .JPG or .PNG ( or .GIF for that matter) you can scan the directory with PHP to look for all files ( can be really intensive though! ) to look for files with the name given.
For example:
<?php
foreach( scandir('/path/to/resale_certificates/') as $file ){
if( $file != '.' && $file != '..'){
// explode so we remove the last extension path ( not type safe ! )
$arguments = explode('.', $file);
// store the last part
$ext = end($arguments);
// pop the extension from the $arguments array so we are left
// with whatever was left
array_pop($arguments);
// concatenate the $arguments into a single string again
$filename = implode('.', $arguments);
// now we can check the filename again
if( $filename == $theirEncrypt){
unlink('/path/to/resale_certificates/' . $filename . '.' . $ext);
}
}
}
edit:
the $file is a string from the $files array returned by the scandir(); function. The single and double dot are a ways to navigate to the current (.) and the parent (..) directory and are therefore symlinks. Another option would be to check if the $file is actually a file. You could replace the comparison line with a is_file('/path/to/resale_certificates/' . $file) to check if it's a file or a symlink ( like the . and the .. ) but it's even more intensive then to check string comparison. In your usecase it is not neccesary.
On a related note, this is quite intensive, depending on the number of clients and certificates you have, you could, as an alternative, store the filename to storage (i.e. database or something similiar) and just unlink the file find there, this would save you to iterate over each file and simply unlink the file directly.
If you know a name of previously uploaded image then you can do the following before saving a new image:
<?php
$previousImageName = 'theirEncrypt.png';
unlink(APP_DIR . "/resale_certificates/" . $previousImageName);
I am attempting a CMS photo gallery and need to create thumbnails at the end of my upload.php file. I have a function called create_square_image that works fine when run on the 'showphotos.php' page. However I don't want it to be run every time someone views the page. I have tried adding the following to SWFUpload...
// Process the file
/*
At this point we are ready to process the valid file. This sample code shows how to save the file. Other tasks
could be done such as creating an entry in a database or generating a thumbnail.
Depending on your server OS and needs you may need to set the Security Permissions on the file after it has
been saved.
*/
$thumb_save = "uploads/thumbs/thumb_" . $_FILES[$upload_name]["tmp_name"];
create_square_image($_FILES[$upload_name]["tmp_name"],$thumb_save,100);
if (!#move_uploaded_file($_FILES[$upload_name]["tmp_name"], $save_path.$file_name)) {
HandleError("File could not be saved.");
exit(0);
}
exit(0);
The create_square_image function uses this format:
create_square_image ( string $filename , string $destination, size )
I have tried it a few times and it will save the image but not the thumbnail.
Set the permissions on /uploads/thumbs/ to 777. You could also try specifying the absolute path to that location. To see your absolute path use this code: echo getcwd();
While uploading images files on the live server I have stuck in a strange issue that the move_uploaded_files() function returns true but the image does not get uploaded.
if(move_uploaded_file($_FILES["img"]["tmp_name"],'./shot_images/'.$_FILES["img"]["name"])){
echo "Success";
}
Here, when executed, prints "Success" but the file is not being uploaded on the specified location.
Any kind of help is appreciated.
If move_uploaded_file is returning true then that indicates the file was moved successfully. Let's try some debugging. What happens when you use the following code:
$dest = "./shot_images/{$_FILES["img"]["name"]}";
if(move_uploaded_file($_FILES["img"]["tmp_name"],$dest)){
$realpath = realpath($dest);
$filesize = filesize($realpath);
echo "Success! Uploaded a $filesize file to $realpath";
}
I suspect it is working, it's just not going where you expect...
If this is the case, it might be due to `'./shot_images/' -- personally I rarely (if ever) use relative paths like that. I find it eliminates confusion if I reference the path to the script:
$dest = dirname(__FILE__)."/shot_images/{$_FILES["img"]["name"]}";
if(move_uploaded_file($_FILES["img"]["tmp_name"],$dest)){
how can I copy two times the same file? I'm trying to do something like this:
copy($file['tmp_name'], $folder."1.jpg");
copy($file['tmp_name'], $folder."2.jpg");
copy($file['tmp_name'], $folder."3.jpg");
And how many time does temp files has before it's destroyed by the server?
I try using move_uploaded_file also, but I can't make it work. I want to generate 2 thumbs from an uploaded file.
Some help?
Thanks,
move_uploaded_file will move the file, and not copy it -- which means it'll work only once.
If you are using copy, there shouldn't be any limit at all on the number of times you can copy : the temporay file created by the upload will only be destroyed at the end of the execution of your script (unless you move/delete it before, of course)
Still, maybe a solution would be to use move_uploaded_file first, and, then, copy ?
A bit like that, I suppose :
if (move_uploaded_file($file['tmp_name'], $folder . '1.jpg')) {
copy($folder . '1.jpg', $folder . '2.jpg');
copy($folder . '1.jpg', $folder . '3.jpg');
}
This would allow you to get the checks provided by move_uploaded_file...
If this doesn't work, then, make sure that :
$folder contains what you want -- including the final /
That $file['tmp_name'] also contains what you want (I'm guessing this is some kind of copy of $_FILES -- make sure the copy of $_FILES to $file is done properly)
Why doesn't move_uploaded_file() work? Are you trying to use it twice? You can't do that, it moves it, so the second time will fail.
I would just use move_uploaded_file() once, and then make the second copy from the location you just moved it to:
move_uploaded_file($uploaded, $destination);
copy($destination, $destination2);
I don't have a reply to your question directly but how about this workaround ?
copy($file['tmp_name'], $folder."1.jpg");
copy($folder."1.jpg" , $folder."2.jpg");
copy($folder."1.jpg" , $folder."3.jpg");
Thanks man, you give me the light.
I made something like this:
$objUpload = new Upload();
$filename = $objUpload->uploadFile($newFile,$folder);
// returns a string
$objUpload->makeThumb($filename,$folder,"thumbs",139);
// makes a 139px thumbnail from the original file uploaded on the first step
$objUpload->makeThumb($filename,$folder,"mini",75);
// makes another thumb from the same file
Using move_ulploaded_file and copy we can make only one thumb. :)