PHP skip case sensitivity in file extension - php

I have rows on my database table which some are not synchronized on the directory.
ex. on my table I have
image.png
but on my directory I have
image.PNG
now, Im having a problem to check if
file_exist
because of the case sensitivity.
I can't choose the option to synchronize my database and my files on the directory manually because it is too many.
May I know how can I used the file_exist that ignores the sensitivity of file types?

For a more general solution, see the comments in the php docs:
General Solution
Which offers this version of the function:
/**
* Alternative to file_exists() that will also return true if a file exists
* with the same name in a different case.
* eg. say there exists a file /path/product.class.php
* file_exists('/path/Product.class.php')
* => false
* similar_file_exists('/path/Product.class.php')
* => true
*/
function similar_file_exists($filename) {
if (file_exists($filename)) {
return true;
}
$dir = dirname($filename);
$files = glob($dir . '/*');
$lcaseFilename = strtolower($filename);
foreach($files as $file) {
if (strtolower($file) == $lcaseFilename) {
return true;
}
}
return false;
}

Create a function that checks both extensions and use it instead of file_exist directly.

As i think, your root cause is due to following--
If your database have "image.png" and in directory "image.PNG" means there is some problem with your insert query.
It must be same in both the places. It better to advice to store file name in lowercase as Linux systems are case sensitive.

Related

PHP unlink file with no extension

I am trying to unlink files in a Directory which have no extensions.
I did following, but did not work:
$fileInfo = pathinfo($this->outputPath);
if($fileInfo['extension'] == NULL)
{
unlink($fileInfo['dirname'].$fileInfo['basename']);
}
according to the pathinfo manual :
Note:
If the path does not have an extension, no extension element
will be returned (see second example below).
so you need to check if the returned value has the extension element using isset , note that using empty will pass the dot directories in unix systems, for example if you are iterating some directory empty will consider the . and .. directories as an empty extension elements
// check if not isset
if(isset($fileInfo['extension']) === false) {
// perform some action
}
or if in the future you want to perform some complex search [eg: recursive search for files that does not have extensions] you may use FilesystemIterator
foreach (new FilesystemIterator($dir) as $fileInfo) {
// check if some file extension is null
if ($fileInfo->getExtension() == null) {
// perform some action
}
}
As #CBroe noticed in comments:
Your comparison with NULL is just wrong here.
Check for empty'ness instead:
$fileInfo = pathinfo($this->outputPath);
if(empty($fileInfo['extension']))
{
unlink($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['basename']);
}
Also, you missed a DIRECTORY_SEPARATOR between the dirname and the basename.
Update: As #hassan pointed out, empty is not the proper way to check for this either. That's because of directories . and .. on unix-like systems will pass this test, which is not desired.
So, the proper way to check for files without extension would be:
if(isset($fileInfo['extension']) === false)
{
unlink($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['basename']);
}

Using PHP how can you tell if the image already exists on your server regardless of name?

I have seen several websites where if you upload an image and an identical image already exists on there servers they will reject the submission. Using PNGs is there an easy way to check one image against a massive folder of images?
http://www.imagemagick.org/discourse-server/viewtopic.php?t=12618
I did find this with imagemagick, but I am looking for one vs many and not one to one a million
You can transform the file content into a sha1. That will give you a way to identify two pictures strictly identical.
see http://php.net/manual/fr/function.sha1-file.php
Then after you save it into a NFS, or use some kind of database to test if the hash already exists.
Details of the images are probably maintained in a database; while the images are stored in the filesystem. And that database probably has a hash column which is used to store an md5 hash of the image file itself, calculated when the image is first uploaded. When a new image is uploaded, it calculates the hash for that image, and then checks to see if any other image detail in the database has a matching hash. If not, it stores the newly uploaded image with that hash; otherwise it can respond with details of the previous upload. If the hash column is indexed in the table, then this check is pretty quick.
If I understood your question correctly. You want to find out if a specific image exists in a Directory with so many images, right? If so, take a look at the solution:
<?php
// CREATE A FUNCTION WHICH RETURNS AN ARRAY OF ALL IMAGES IN A SPECIFIC FOLDER
function getAllImagesInFolder($dir_full_path){
$returnable = array();
$files_in_dir = scandir($dir_full_path);
$reg_fx = '#(\.png|\.jpg|\.bmp|\.gif|\.jpeg)#';
foreach($files_in_dir as $key=>$val){
$temp_file_or_dir = $dir_full_path . DIRECTORY_SEPARATOR . $val;
if(is_file($temp_file_or_dir) && preg_match($reg_fx, $val) ){
$regx_dot_wateva = '/\.{2,4}$/';
$regx_dot = '/\./';
$regx_array = array($regx_dot_wateva, $regx_dot);
$replace_array = array("", "_");
$return_val = preg_replace($regx_array, $replace_array, $val);
$returnable[$return_val] = $temp_file_or_dir ;
}else if(is_dir($temp_file_or_dir) && !preg_match('/^\..*/', $val) ){
getFilesInFolder($temp_file_or_dir);
}
}
return $returnable;
}
// CREATE ANOTHER FUNCTION TO CHECK IF THE SPECIFIED IMAGE EXISTS IN THE GIVEN DIRECTORY.
// THE FIRST PARAMETER SHOULD BE THE RESULT OF CALLING THE PREVIOUS FUNCTION: getAllImagesInFolder(...)
// THE SECOND PARAMETER IS THE IMAGE YOU WANT TO SEARCH WHETHER IT EXISTS IN THE SAID FOLDER OR NOT
function imageExistsInFolder($arrImagesInFolder, $searchedImage){
if(!is_array($arrImagesInFolder) && count($arrImagesInFolder) < 1){
return false;
}
foreach($arrImagesInFolder as $strKey=>$imgPath){
if(stristr($imgPath, $searchedImage)){
return true;
}
}
return false;
}
// NOW GET ALL THE IMAGES IN A SPECIFIED FOLDER AND ASSIGN THE RESULTING ARRAY TO A VARIABLE: $imgFiles
$imgFolder = "/path/to/directory/where/there/are/images";
$arrImgFiles = getAllImagesInFolder($imgFolder);
$searchedImage = "sandwich.jpg"; //<== OR EVEN WITHOUT THE EXTENSION, JUST "sandwich"
// ASSUMING THE SPECIFIC IMAGE YOU WANT TO MATCH IS CALLED sandwich.jpg
// YOU CAN USE THE imageExistsInFolder(...) FUNCTION TO RETURN A BOOLEAN FLAG OF true OR false
// DEPENDING ON IF IT DOES OR NOT.
var_dump($arrImgFiles);
var_dump( imageExistsInFolder($arrImgFiles, $searchedImage) );

Copy and rename multiple files with PHP

Is there a way to copy and rename multiple files in php but get their names from an array or a list of variables.
The nearest thing to what I need that I was able to find is this page
Copy & rename a file to the same directory without deleting the original file
but the only thing the script on this page does is creating a second file and it's name is already preset in the script.
I need to be able to copy and create multiple files, like 100-200 and get their names set from an array.
If I have an initial file called "service.jpg"
I would need the file to be copied multiple times with the different names from the array as such :
$imgnames = array('London', 'New-York','Seattle',);
etc.
Getting a final result of 3 separate files called "service-London.jpg", "service-New-York.jpg" and so on.
I'm sure that it should be a pretty simple script, but my knowledge of PHP is really insignificant at the time.
One approach (untested) that you can take is creating a class to duplicate a directory. You mentioned you would need to get the name of the files in a directory and this approach will handle it for you.
It will iterate over an array of names (whatever you pass to it), and copy/rename all of the files inside a directory of your choice. You might want to add some checks in the copy() method (file_exists, etc) but this will definitely get you going and is flexible.
// Instantiate, passing the array of names and the directory you want copied
$c = new CopyDirectory(['London', 'New-York', 'Seattle'], 'location/of/your/directory/');
// Call copy() to copy the directory
$c->copy();
/**
* CopyDirectory will iterate over all the files in a given directory
* copy them, and rename the file by appending a given name
*/
class CopyDirectory
{
private $imageNames; // array
private $directory; // string
/**
* Constructor sets the imageNames and the directory to duplicate
* #param array
* #param string
*/
public function __construct($imageNames, $directory)
{
$this->imageNames = $imageNames;
$this->directory = $directory;
}
/**
* Method to copy all files within a directory
*/
public function copy()
{
// Iterate over your imageNames
foreach ($this->imageNames as $name) {
// Locate all the files in a directory (array_slice is removing the trailing ..)
foreach (array_slice(scandir($this->directory),2) as $file) {
// Generates array of path information
$pathInfo = pathinfo($this->directory . $file);
// Copy the file, renaming with $name appended
copy($this->directory . $file, $this->directory . $pathInfo['filename'] . '-' . $name .'.'. $pathInfo['extension']);
}
}
}
}
You could use a regular expression to build the new filenames, like this:
$fromFolder = 'Images/folder/';
$fromFile = 'service.jpg';
$toFolder = 'Images/folder/';
$imgnames = array('London', 'New-York','Seattle');
foreach ($imgnames as $imgname) {
$newFile = preg_replace("/(\.[^\.]+)$/", "-" . $imgname . "$1", $fromFile);
echo "Copying $fromFile to $newFile";
copy($fromFolder . $fromFile, $toFolder . $newFile);
}
The above will output the following while copying the files:
Copying service.jpg to service-London.jpg
Copying service.jpg to service-New-York.jpg
Copying service.jpg to service-Seattle.jpg
In the above code, set the $fromFolder and $toFolder to your folders, they can be the same folder, if so needed.

upload images through php using unique file names

I am currently in the process of writing a mobile app with the help of phonegap. One of the few features that I would like this app to have is the ability to capture an image and upload it to a remote server...
I currently have the image capturing and uploading/emailing portion working fine with a compiled apk... but in my php, I am currently naming the images "image[insert random number from 10 to 20]... The problem here is that the numbers can be repeated and the images can be overwritten... I have read and thought about just using rand() and selecting a random number from 0 to getrandmax(), but i feel that I might have the same chance of a file overwriting... I need the image to be uploaded to the server with a unique name every-time, no matter what... so the php script would check to see what the server already has and write/upload the image with a unique name...
any ideas other than "rand()"?
I was also thinking about maybe naming each image... img + date + time + random 5 characters, which would include letters and numbers... so if an image were taken using the app at 4:37 am on March 20, 2013, the image would be named something like "img_03-20-13_4-37am_e4r29.jpg" when uploaded to the server... I think that might work... (unless theres a better way) but i am fairly new to php and wouldn't understand how to write something like that...
my php is as follows...
print_r($_FILES);
$new_image_name = "image".rand(10, 20).".jpg";
move_uploaded_file($_FILES["file"]["tmp_name"], "/home/virtual/domain.com/public_html/upload/".$new_image_name);
Any help is appreciated...
Thanks in advance!
Also, Please let me know if there is any further info I may be leaving out...
You may want to consider the PHP's uniqid() function.
This way the code you suggested would look like the following:
$new_image_name = 'image_' . date('Y-m-d-H-i-s') . '_' . uniqid() . '.jpg';
// do some checks to make sure the file you have is an image and if you can trust it
move_uploaded_file($_FILES["file"]["tmp_name"], "/home/virtual/domain.com/public_html/upload/".$new_image_name);
Also keep in mind that your server's random functions are not really random. Try random.org if you need something indeed random. Random random random.
UPD: In order to use random.org from within your code, you'll have to do some API requests to their servers. The documentation on that is available here: www.random.org/clients/http/.
The example of the call would be: random.org/integers/?num=1&min=1&max=1000000000&col=1&base=10&format=plain&rnd=new. Note that you can change the min, max and the other parameters, as described in the documentation.
In PHP you can do a GET request to a remote server using the file_get_contents() function, the cURL library, or even sockets. If you're using a shared hosting, the outgoing connections should be available and enabled for your account.
$random_int = file_get_contents('http://www.random.org/integers/?num=1&min=1&max=1000000000&col=1&base=10&format=plain&rnd=new');
var_dump($random_int);
You should use tempnam() to generate a unique file name:
// $baseDirectory Defines where the uploaded file will go to
// $prefix The first part of your file name, e.g. "image"
$destinationFileName = tempnam($baseDirectory, $prefix);
The extension of your new file should be done after moving the uploaded file, i.e.:
// Assuming $_FILES['file']['error'] == 0 (no errors)
if (move_uploaded_file($_FILES['file']['tmp_name'], $destinationFileName)) {
// use extension from uploaded file
$fileExtension = '.' . pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
// or fix the extension yourself
// $fileExtension = ".jpg";
rename($destinationFileName, $destinationFileName . $fileExtension);
} else {
// tempnam() created a new file, but moving the uploaded file failed
unlink($destinationFileName); // remove temporary file
}
Have you considered using md5_file ?
That way all of your files will have unique name and you would not have to worry about duplicate names. But please note that this will return same string if the contents are the same.
Also here is another method:
do {
$filename = DIR_UPLOAD_PATH . '/' . make_string(10) . '-' . make_string(10) . '-' . make_string(10) . '-' . make_string(10);
} while(is_file($filename));
return $filename;
/**
* Make random string
*
* #param integer $length
* #param string $allowed_chars
* #return string
*/
function make_string($length = 10, $allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890') {
$allowed_chars_len = strlen($allowed_chars);
if($allowed_chars_len == 1) {
return str_pad('', $length, $allowed_chars);
} else {
$result = '';
while(strlen($result) < $length) {
$result .= substr($allowed_chars, rand(0, $allowed_chars_len), 1);
} // while
return $result;
} // if
} // make_string
Function will create a unique name before uploading image.
// Upload file with unique name
if ( ! function_exists('getUniqueFilename'))
{
function getUniqueFilename($file)
{
if(is_array($file) and $file['name'] != '')
{
// getting file extension
$fnarr = explode(".", $file['name']);
$file_extension = strtolower($fnarr[count($fnarr)-1]);
// getting unique file name
$file_name = substr(md5($file['name'].time()), 5, 15).".".$file_extension;
return $file_name;
} // ends for is_array check
else
{
return '';
} // else ends
} // ends
}

Protecting variables from "include pollution" in PHP

tl;dr: Is there a way to prevent alteration to (essentially lock) variables declared/defined prior to an include() call, by the file being included? Also, somewhat related question.
I'm wondering about what measures can be taken, to avoid variable pollution from included files. For example, given this fancy little function:
/**
* Recursively loads values by include returns into
* arguments of a callback
*
* If $path is a file, only that file will be included.
* If $path is a directory, all files in that directory
* and all sub-directories will be included.
*
* When a file is included, $callback is invoked passing
* the returned value as an argument.
*
* #param string $path
* #param callable $callback
*/
function load_values_recursive($path, $callback){
$paths[] = path($path);
while(!empty($paths)){
$path = array_pop($paths);
if(is_file($path)){
if(true === $callback(include($path))){
break;
}
}
if(is_dir($path)){
foreach(glob($path . '*') as $path){
$paths[] = path($path);
}
}
}
}
I know it's missing some type-checking and other explanations, let's ignore those.
Anyways, this function basically sifts through a bunch of "data" files that merely return values (typically configuration arrays, or routing tables, but whatever) and then invokes the passed callback so that the value can be filtered or sorted or used somehow. For instance:
$values = array();
load_values_recursive('path/to/dir/', function($value) use(&$values){
$values[] = $value;
});
And path/to/dir/ may have several files that follow this template:
return array(
// yay, data!
);
My problem comes when these "configuration" files (or whatever, trying to keep this portable and cross-functional) start to contain even rudimentary logic. There's always the possibility of polluting the variables local to the function. For instance, a configuration file, that for the sake of cleverness does:
return array(
'path_1' => $path = 'some/long/complicated/path/',
'path_2' => $path . 'foo/',
'path_3' => $path . 'bar/',
);
Now, given $path happens to be a visible directory relative to the current, the function is gonna go wonky:
// ...
if(is_file($path)){
if(true === $callback(include($path))){ // path gets reset to
break; // some/long/complicated/path/
}
}
if(is_dir($path)){ // and gets added into the
foreach(glob($path . '*') as $path){ // search tree
$paths[] = path($path);
}
}
// ...
This would likely have bad-at-best results. The only1 solution I can think of, is wrapping the include() call in yet another anonymous function to change scope:
// ...
if(true === call_user_func(function() use($callback, $path){
return $callback($path);
})){
break;
}
// ...
Thus protecting $path (and more importantly, $callback) from causing side effects with each iteration.
I'm wondering if there exists a simpler way to "lock" variables in PHP under such circumstances.
I just wanna go on the record here; I know I could use, for instance, an elseif to alleviate one of the issues specific to this function, however my question is more interested in circumstance-agnostic solutions, a catch-all if you will.
take a look at Giving PHP include()'d files parent variable scope it has a rather unique approach to the problem that can be used here.
it amounts to unsetting all defined vars before the include and then resetting them after.
it certainly isn't elegant, but it'll work.
I've gone with the following solution to include pollution:
$value = call_user_func(function(){
return include(func_get_arg(0));
}, $path);
$path is nowhere to be seen at inclusion, and it seems most elegant. Surely, calling func_get_arg($i) from the included file will yield passed values, but, well...

Categories