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.
Related
I have a directory with name 2019. I want to create a ZIP file which contains all the pdf files inside the folders 01-03. In a for loop, I fill an array with all the paths of the directories who are not empty. Now I don't know how to open a stream or something else to put the array values inside in a for loop and recursively add all pdfs under each subfolder path inside it. Any idea guys?
for ($i = 1; $i < 4; $i++) {
// for the 3 months of this year
$absolutepath = "$year_path/0$i";
if (file_exists($absolutepath) && glob($absolutepath . "/*")) {
// check if path/year/month exists
// check if folder contains any files
// store specific full paths inside array for use
array_push($path_array, $absolutepath);
}
}
// how can i put here $path_array into a function to create zip file which contains all the pdfs under each subfolder path of the $path_array ???
It looks like you are creating the string wrong. You have to concatenate the variables outside of the string for the path separator with the leading zero. I think it should be:
$absolutepath = $year_path + "/0" + $i;
I used php real path to get actual path of files and directory to delete and after deleted i will print all deleted
items. But my problem is that it also show the real path where the file source is and i don't want to show it to users
is there any way i can hide the pay and only show the file example.
I don't like it to look like this
[File]: /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg
[File]: /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/room_home_1.jpg
[Directory]: /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder
Is there anyway i can make it look this way using rejex or any method please i need help i have to remove /mnt/wef66/d2/81/557642661/htdocs/
[File]: www.example.com/useruploads/myfiles/imagefolder/mosaic_1.jpg
[File]: www.example.com/useruploads/myfiles/imagefolder/room_home_1.jpg
[Directory]: www.example.com/useruploads/myfiles/imagefolder
Maybe using something like this
echo preg_replace("/mnt/wef66/d2/81/557642661/htdocs", "www.example.com", "[File]: /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg");
$path = realpath($parentBas);
I would use configuration variables $privatePath and $publicPath.
So you can concat whichever you want to the relative paths to your directories or files.
For your example:
$privatePath = '/mnt/wef66/d2/81/557642661/htdocs/';
$publicPath = 'www.example.com/';
$pic1RelativePath = 'useruploads/myfiles/imagefolder/mosaic_1.jpg';
$pic1privatePath = $privatePath . $pic1RelativePath;
// /mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg
$pic1publicPath = $publicPath . $pic1RelativePath;
// www.example.com/useruploads/myfiles/imagefolder/mosaic_1.jpg
I think this is easier and more efficient than replacing the paths with regex.
EDIT:
If you have all the real paths in an array, you can loop through it and replace easily all the private paths with the public paths this way:
$paths = [
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/mosaic_1.jpg',
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder/room_home_1.jpg',
'/mnt/wef66/d2/81/557642661/htdocs/useruploads/myfiles/imagefolder'
];
foreach ($paths as &$path) {
$path = str_replace($privatePath, $publicPath, $path);
}
print_r($paths);
Have found 2 threads on this here at Stackoverflow, hovever these are about how to return an array. I can generate an array inside the function and it is having the right content, however when doing var_dumping of $target_file outside the function it is NULL. Otherwise the code is doing what it is supposed to do.
Is it a scope thing? or...have I done something completely wrong here?
Can anyone please help me access the returned array outside the function?
function copy_files3($requested, $src_path, $send_path){
//function copy_files renames and copies pdf-files to a specific folder.
//ARRAY $requested (keys INT), (names STR) holds the names of the selected files
//STR $src_path is the full path to the requested files
//STR $send_path is the full path to the re-named files
//ARRAY $target_file holds the names of the renamed files
$i=0;
$target_file = array();
$src_filename = array();
$b=array();
foreach($requested as $value) {
//$value holds the names of the selected files.
//1 Expand to get the full path to the source file
//2 Generate a 10 char + .pdf (aka 14 char) long new file name for the file.
//3 Generate full path to the new file.
$src_filename[$i] = $src_path.$value;
$rnam[$i] = randomstring(); //function randomstring returns a 10 char long random string
$target_file[$i] = $send_path.$rnam[$i].'.pdf';
echo 'target_file['.$i.'] = '.$target_file[$i].'<br>';
copy($src_filename[$i],$target_file[$i]);
$i++;
}
return($target_file);
}
I have files renamed and placed in the correct folders on my server, the only problem is accessing the $target_file array after this function.
$target_file exists only inside the function. And yes, it's a scope thing.
You are returning this variable's value, but not the variable itself.
All you have to do is to assign returned value to some variable while invoking the function.
$returnedValue = copy_files3($requested, $src_path, $send_path);
Now, $returnedValue has the same value as $target_file had inside the function.
<?php
function copy_files3($requested, $src_path, $send_path){
//function copy_files renames and copies pdf-files to a specific folder.
//ARRAY $requested (keys INT), (names STR) holds the names of the selected files
//STR $src_path is the full path to the requested files
//STR $send_path is the full path to the re-named files
//ARRAY $target_file holds the names of the renamed files
$i=0;
$target_file = array();
$src_filename = array();
$b=array();
foreach($requested as $value) {
//$value holds the names of the selected files.
//1 Expand to get the full path to the source file
//2 Generate a 10 char + .pdf (aka 14 char) long new file name for the file.
//3 Generate full path to the new file.
$src_filename[$i] = $src_path.$value;
$rnam[$i] = randomstring(); //function randomstring returns a 10 char long random string
$target_file[$i] = $send_path.$rnam[$i].'.pdf';
echo 'target_file['.$i.'] = '.$target_file[$i].'<br>';
copy($src_filename[$i],$target_file[$i]);
$i++;
}
return($target_file);
}
$returnedValue = copy_files3($requested, $src_path, $send_path);
?>
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...
In the script below, I'm attempting to iterate over the folders and files inside of the $base folder. I expect it to contain a single level of child folders, each containing a number of .txt files (and no subfolders).
I'm just needing to understand how to reference the elements in comments below...
Any help much appreciated. I'm really close to wrapping this up :-)
$base = dirname(__FILE__).'/widgets/';
$rdi = new RecursiveDirectoryIterator($base);
foreach(new RecursiveIteratorIterator($rdi) as $files_widgets)
{
if ($files_widgets->isFile())
{
$file_name_widget = $files_widgets->getFilename(); //what is the filename of the current el?
$widget_text = file_get_contents(???); //How do I reference the file here to obtain its contents?
$sidebar_id = $files_widgets->getBasename(); //what is the file's parent directory name?
}
}
//How do I reference the file here to obtain its contents?
$widget_text = file_get_contents(???);
$files_widgets is a SplFileInfo, so you have a few options to get the contents of the file.
The easiest way is to use file_get_contents, just like you are now. You can concatenate together the path and the filename:
$filename = $files_widgets->getPathname() . '/' . $files_widgets->getFilename();
$widget_text = file_get_contents($filename);
If you want to do something funny, you can also use openFile to get a SplFileObject. Annoyingly, SplFileObject doesn't have a quick way to get all of the file contents, so we have to build a loop:
$fo = $files_widgets->openFile('r');
$widget_text = '';
foreach($fo as $line)
$widget_text .= $line;
unset($fo);
This is a bit more verbose, as we have to loop over the SplFileObject to get the contents line-by-line. While this is an option, it'll be easier for you just to use file_get_contents.