Resize images inside folder and subfolders - php

I have this PHP code that resizes images perfectly: smart_resize_image(path/to/image.jpg);
Now I want to run it on all images inside a folder say parent and all of its subfolders child1, child2 etc.. every hour.
Is this something i could do on a share host? Yes, I can setup cron but I'm not sure how to run it on folders and its subfolders.
Thanks!

You're looking for a recursive algorithm, to drill down through folders:
resizing( '/folder' );
function resizing( $folder )
{
foreach( scandir( $folder ) as $file )
{
$filepath = $folder . '/' . $file;
if( preg_match( '/^\./', $file ) ) continue; // not . and ..
if( is_dir( $filepath ) ) resizing( $filepath ); // Send it off to drill - with this function!!
// It's time to resize
smart_resize_image( $filepath );
}
}

you may lookup for files using glob function and then loop the results through your resize method. Be aware as it must be done by cron as it probably will take more time that allowed in a webserver script context.

You have to build a recursive function.
It is quite simple.
Just start reading first directory and if you find any directories for each make a callback to itself to parse each folder.
It's not a very consuming function.
See this: http://www.codingforums.com/showthread.php?t=71882
Dump all file matching your desired extensions to an array then run your resize function for them.
To avoid any memory issues you can call the resize via CLI.
Just make a file that will take the file path as an argument (not argument not get) and call it with shell_exec().
This way it will run them nicely one by one in a separate process without affecting the main one.
Multi-processing in PHP .. hehe

Related

Replace save files if from same User

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);

Is there any quick way to add same php file to many folders?

I have a index.php file. In my root folder, there are approximately 200 folders. I want to add index.php file to all 200 folder. Instead of copy-paste, is there a quick way to add it?
There is a quick way to do this but I feel there are better ways to do what you need.
Is the index file purely to stop people seeing folders?
If so try putting IndexIgnore * into your .htaccess
More info here: http://www.javascriptkit.com/howto/htaccess11.shtml
Well, like all the other people have already said, there is probably something wrong in your design. If you want to make sure people can't access it, just use Apache to do that, not PHP. If you still feel the need to add an index.php file to every single directory, here's how:
<?php
$content = 'Your content';
$files = glob( './*' );
foreach( $files as $file ) {
if( is_dir( $file ) && is_writable( $file ) ) {
file_put_contents( $file . '/index.php', $content );
}
}
Use this function:
function putindexfiles($putfile,$start=""){
$files = glob($start.'*',GLOB_MARK);
foreach($files as $file){
if(is_dir($file)){
copy($putfile,$file.'index.php');
putindexfiles($putfile,$file);
}
}
}
This function use recursion so all sub-directories also get affected.
and $putfile is the path to the file whose contents are to be placed in index.php of every folder. this script creates all index.php automatically in each folder.
while using the function you dont need to provide the $start as this is default parameter is the directory in which the script is placed.
Enjoy

PHP Script takes almost 15 seconds to load

I've written a PHP script that iterates through a given folder, extracts all the images from there and displays them on an HTML page (as tags). The size of the page is about 14 KB, but it takes the page almost 15 seconds.
Here's the code:
function displayGallery( $gallery, $rel, $first_image ) {
$prefix = "http://www.example.com/";
$path_to_gallery = "gallery_albums/" . $gallery . "/";
$handler = opendir( $path_to_gallery ); //opens directory
while ( ( $file = readdir( $handler ) ) !== false ) {
if ( strcmp( $file, "." ) != 0 && strcmp( $file, ".." ) !=0 ) {
//check for "." and ".." files
if ( isImage( $prefix . $path_to_gallery . $file ) ) {
echo '';
}
}
}
closedir( $handler ); //closes directory
}
function isImage($image_file) {
if (getimagesize($image_file)!==false) {
return true;
} else {
return false;
}
}
I looked at other posts, but most of them deal with SQL queries, and that's not my case.
Any suggestions how to optimize this?
You can use a PHP profiler like http://xdebug.org/docs/profiler to find what part of the script is taking forever to run. It might be overkill for this issue, but long-term you may be glad you took the time now to set it up.
I suppose that's because you've added $prefix in the isImage invokation. That way this function actually downloads all your images directly from your webserver instead of looking them up locally.
you may use use getimagesize(), it issues E_NOTICE and returns FALSE when file is not a known image type.
An out of left field suggestion here. You don't state how you are clocking the execution time. If you are clocking it in the browser, as in taking 15 seconds to load the page from a link, the problem could have nothing at all to do with your script. I have seen people in the past create similar pages trying to use images as tags, and they take forever to load because even though they are displaying the image at thumbnail size or smaller, the image itself is still 800 x 600 or something. I know it sounds daft, but make sure that you are not just displaying large images in a small size. It would be perfectly reasonable for a script to require 15 seconds to load and display 76 800 x 600 jpegs.
My assumption is that isImage is the problem. I've never seen it before. Why not just check for particular file extensions? That's pretty quick.
Update: You might also try switching to use exif_imagetype() which is likely faster than getimagesize() Putting that check into the top function is also going to be faster. Neither of those functions was meant to be done over a web connection - avoid that altogether. Best to stick with the file extension.
Do you not already have access to the files directly? Every time you look something up over the web, it's going to take a while - you need to wait for the entire file to download. Look up the files directly on your system.
Use scandir to get all the filenames at once into an array and walk through them. That will likely speed things up as I assume there won't be a back and forth to get things individually.
Instead of doing strcmp for . and .. just do $file != '.' && $file != '..'
Also, the speed is going to depend on the number of files being returned, if there are a lot it's going to be slow. The OS can slow down with too many files in a directory as well. You're looping over all files and directories, not just images so that's the number that counts, not just the images.
getimagesize is the problem, it took 99.1% of the script time.
Version #1 - Orignal case
Version #2 - If you really need to use getimagesize with URL (http://). Then a faster alternative, found in http://www.php.net/manual/en/function.getimagesize.php#88793 . It reads only the X first bytes of the image. XHProf shows it is x10 faster. Another ideas also could be using curl multi for parallel download https://stackoverflow.com/search?q=getimagesize+alternative
Version #3 - I think this is the best suitable for your case is to open files as normal files systems without (http://). This is even x100 faster per Xhprof

PHP, search and delete files from directory - performance

I want to delete cache files in a directory, the directory can contain up to 50.000 files. I currently I use this function.
// Deletes all files in $type directory that start with $start
function clearCache($type,$start)
{
$open = opendir($GLOBALS['DOC_ROOT']."/cache/".$type."/");
while( ($file = readdir($open)) !== false )
{
if ( strpos($file, $start)!==false )
{
unlink($GLOBALS['DOC_ROOT']."/cache/".$type."/".$file);
}
}
closedir($open);
}
This works fine and it is fast, but is there any faster way to do this? (scan_dir seems to be slow). I can move the cache to memory obviously.
Thanks,
hamlet
You may want to take a look into the glob function, as it may be even faster... it depends on the C library's glob command to do its work.
I haven't tested this, but I think this would work::
foreach (glob($GLOBALS['DOC_ROOT']."/cache/".$type."/".$start) as $file) {
unlink($GLOBALS['DOC_ROOT']."/cache/".$type."/".$file);
}
Edit: I'm not sure if $file would be just the filename or the entire path. glob's documentation implies just the filename.
Either glob as suggested before or, if you can be certain there won't be malicious input, by issueing directly to the system via exec(sprintf('rm %s/sess*', realpath($path)));, which should be fastest.

Creating a file inside a folder that doesn't exist yet in php

I want my php script to create an output file in a folder based on the date. The way I'm doing this is that its supposed to get the foldername/filename from a text file outputted by another program which I am unable to edit.
So the file its grabbing the data from looks like this:
data/newfolder/10302008/log_for_Today.txt | 24234234
Only with multiple lines, I just need the script to go through it line by line, grab the folder/filename and create an empty file with that name in that location.
The directories are all 777. Now I know how to create a new empty exe file in a folder but can't seem to figure out how to create the folder first then the exe inside of it, any ideas?
if(!file_exists(dirname($file)))
mkdir(dirname($file), 0777, true);
//do stuff with $file.
Use the third parameter to mkdir(), which makes it create directories recursively.
With
$directories = explode( '/', $path );
you can split the path to get single directory names. Then go through the array and create the directories setting chmod 777. (The system user, who executes php must have the ability to do that.)
$file = array_pop( $directories );
$base = '/my/base/dir';
foreach( $directories as $dir )
{
$path = sprintf( '%s/%s', $base, $dir )
mkdir( $path );
chmod( $path, 777 );
$base = $path;
}
// file_put_contents or something similar
file_put_contents( sprintf( '%s/%s', $base, $file ), $data );
The problem here is that you might not set chmod from your php script.
An alternative could be to use FTP. The user passes FTP login data to the script and it uses FTP functionality to manage files.
http://www.php.net/FTP
It's little too late but I found this question and I have a solution for this, here is an example code and it works good for me no matter how deep is your file. You should change directory separator for lines 1 and 3 if you're running it on Windows server.
$pathToFile = 'test1/test2/test3/test4/test.txt';
$fileName = basename($pathToFile);
$folders = explode('/', str_replace('/' . $fileName, '', $pathToFile));
$currentFolder = '';
foreach ($folders as $folder) {
$currentFolder .= $folder . DIRECTORY_SEPARATOR;
if (!file_exists($currentFolder)) {
mkdir($currentFolder, 0755);
}
}
file_put_contents($pathToFile, 'test');
Best regards, Georgi!
Create any missing folders using mkdir(), then create the empty file using touch().
You can use absolute paths in both cases, meaning:
mkdir('data');
mkdir('data/newfolder');
mkdir('data/newfolder/10302008');
touch('data/newfolder/10302008/log_for_Today.txt');
if you're curious about where it's starting-point it will be, you can use getcwd() to tell you the working directory.
Can't you just do this by creating the dir with mkdir (http://nl.php.net/manual/en/function.mkdir.php) then chmod it 777 (http://nl.php.net/manual/en/function.chmod.php) the change directory with chdir (http://nl.php.net/manual/en/function.chdir.php) and then create the file (touch)?

Categories