If I have a file called file.html how do i make 10 clones of this file via PHP such that they are renamed file1....file10?
$filename = 'file.html'
$copyname = 'file2.html'
if ($file = #fopen($copyname, 'x')) {
// We've successfully created a file, so it's ours. We'll close
// our handle.
if (!#fclose($file)) {
// There was some problem with our file handle.
return false;
}
// Now we copy over the file we created.
if (!#copy($filename, $copyname)) {
// The copy failed, even though we own the file, so we'll clean
// up by itrying to remove the file and report failure.
unlink($copyname);
return false;
}
return true;
}
Small file approach: this allows you to do something with the contents of the file before saving it:
$text = file_get_contents('file.html');
for($i = 0; $i < 100; $i++) {
file_put_contents('file'.$i.'.html', $data);
}
Bigger files approach: this does not allow you to access the contents of the file before saving it, it only tells the underlying OS to make the copy (equivalent to a linux bash command of cp file.html file1.html):
for($i = 0; $i < 100; $i++) {
copy('file.html', 'file'.$i.'.html');
}
Just run your code in a loop:
$filename = 'file.html'
for($i=1; $i<=10; $i++) {
$copyname = "file$i.html";
copy($filename, $copyname);
}
Feel free to add error checking and handling.
Related
I have a number of different hosting accounts set up for clients and need to calculate the amount of storage space being used on each account, which would update regularly.
I have a database set up to record each clients storage usage.
I attempted this first using a PHP file on each account, run by a Cron Job. If run manually by myself, it would output the correct filesize and update the correct size to the database, although when run from the Cron Job, it would output 0.
I then attempted to run this file from a Cron Job from the main account but figured this wouldn't actually work as my hosting would block files from another server and I would end up with the same result as before.
I am now playing around with FTP access to each account from a Cron Job from the main account which looks something like below, the only problem is I don't know how to calculate directory size rather than single file sizes using FTP access, and don't know how to reiterate this way? Hoping somebody might be able to help here before I end up going around in circles?
I will also add the previous first attempt too.
$ftp_conn = ftp_connect($ftp_host, 21, 420) or die("Could not connect to server");
$ftp_login = ftp_login($ftp_conn, $ftp_username, 'mypassword');
$total_size = 0;
$contents = ftp_nlist($ftp_conn, ".");
// output $contents
foreach($contents as $folder){
while($search == true){
if($folder == '..' || $folder == '.'){
} else {
$file = $folder;
$res = ftp_size($ftp_conn, $file);
if ($res != -1) {
$total_size = $total_size + $res;
} else {
$total_size = $total_size;
}
}
}
}
ftp_close($ftp_conn);
This doesn't work as it doesn't calculate folder sizes and I don't know how to open the reiterate using this method?
This second script did work but would only work if opened manually, and return 0 if run by the cron job.
class Directory_Calculator {
function calculate_whole_directory($directory)
{
if ($handle = opendir($directory))
{
$size = 0;
$folders = 0;
$files = 0;
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != "..")
{
if(is_dir($directory.$file))
{
$array = $this->calculate_whole_directory($directory.$file.'/');
$size += $array['size'];
$files += $array['files'];
$folders += $array['folders'];
}
else
{
$size += filesize($directory.$file);
$files++;
}
}
}
closedir($handle);
}
$folders++;
return array('size' => $size, 'files' => $files, 'folders' => $folders);
}
}
/* Path to Directory - IMPORTANT: with '/' at the end */
$directory = '../public_html/';
// return an array with: size, total files & folders
$array = $directory_size->size($directory);
$size_of_site = $array['size'];
echo $size_of_site;
Please bare in mind that I am currently testing and none of the MySQLi or PHP scripts are secure yet.
If your server supports MLSD command and you have PHP 7.2 or newer, you can use ftp_mlsd function:
function calculate_whole_directory($ftp_conn, $directory)
{
$files = ftp_mlsd($ftp_conn, $directory) or die("Cannot list $directory");
$result = 0;
foreach ($files as $file)
{
if (($file["type"] == "cdir") || ($file["type"] == "pdir"))
{
$size = 0;
}
else if ($file["type"] == "dir")
{
$size = calculate_whole_directory($ftp_conn, $directory."/".$file["name"]);
}
else
{
$size = intval($file["size"]);
}
$result += $size;
}
return $result;
}
If you do not have PHP 7.2, you can try to implement the MLSD command on your own. For a start, see user comment of the ftp_rawlist command:
https://www.php.net/manual/en/function.ftp-rawlist.php#101071
If you cannot use MLSD, you will particularly have problems telling if an entry is a file or folder. While you can use the ftp_size trick, as you do, calling ftp_size for each entry can take ages.
But if you need to work against one specific FTP server only, you can use ftp_rawlist to retrieve a file listing in a platform-specific format and parse that.
The following code assumes a common *nix format.
function calculate_whole_directory($ftp_conn, $directory)
{
$lines = ftp_rawlist($ftp_conn, $directory) or die("Cannot list $directory");
$result = 0;
foreach ($lines as $line)
{
$tokens = preg_split("/\s+/", $line, 9);
$name = $tokens[8];
if ($tokens[0][0] === 'd')
{
$size = calculate_whole_directory($ftp_conn, "$directory/$name");
}
else
{
$size = intval($tokens[4]);
}
$result += $size;
}
return $result;
}
Based on PHP FTP recursive directory listing.
Regarding cron: I'd guess that the cron does not start your script with a correct working directory, so you calculate a size of a non-existing directory.
Use an absolute path here:
$directory = '../public_html/';
Though you better add some error checking so that you can see yourself what goes wrong.
I'm facing strange problem right now - "filesize(): stat failed for C:\xampp\tmp\php7A38.tmp" exception. The problem occurs when I'm uploading files in my application built with PHP (Laravel).
Before I'm uploading the files onto the server I'm checking size of files like this (this works very well):
for ($i = 0; $i < $filesLength; $i++) {
if(filesize($request['files'][$i]) < 1572865) {
$file = $request['files'][$i];
$filename = $imageNumber.'.'.$request['files'][$i]->extension();
$file = $file->move(public_path().'/app/newsimages/'.$element->id.'/', $filename);
}
}
If I do it like that everything works very well. But the problem is that I have to put this loop in another loop, like this:
foreach($somelement as $element) {
for ($i = 0; $i < $filesLength; $i++) {
if(filesize($request['files'][$i]) < 1572865) {
$file = $request['files'][$i];
$filename = $imageNumber.'.'.$request['files'][$i]->extension();
$file = $file->move(public_path().'/app/newsimages/'.$element->id.'/', $filename);
}
}
}
In addition to that it crashes at the second loop of the foreach loop.
Maybe you have some idea what's wrong in here?
I think this is obvious, in inner loop you move the file, so when you go to next iteration of outer loop file is not there, so for example if you once move the file:
$request['files'][0]
it's not possible to execute:
filesize($request['files'][0])
because this file was moved - it doesn't exist any more.
I am using PHP to upload a zip file and extracting it. I was having problems with my validation script, and just discovered that the culprit was Thumbs.db files which windows creates to improve caching. How can I delete these files prior to extracting?
Below is my attempt, but when extracting, other files have also been deleted. I've tried using both deleteIndex() and deleteName(), but get the same results. If I comment out the the line which deletes the Thumbs.db files, I do not experience the unintended deleted files. My syslog() line only indicates that the Thumbs.db files are being deleted.
<?php
$zip = new ZipArchive();
if ($zip->open($_FILES['upload_file']['tmp_name']) === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
//Validate files
$name=$zip->getNameIndex($i);
$pieces=explode(DIRECTORY_SEPARATOR,$name);
if($pieces[count($pieces)-1]=='Thumbs.db'){
//Delete windows created thumb.db files
syslog(LOG_INFO,'delete file '.$name.' with index '.$i);
$zip->deleteIndex($i); //If commented out, I do not experience the wrong files being deleted
//Also deletes wrong files: $zip->deleteName($name);
}
}
$zip->extractTo($myPath);
}
?>
Close the archive after file manipulations and reopen it before extracting:
if ($zip->open($_FILES['upload_file']['tmp_name']) === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
...
}
$zip->close();
if ($zip->open($_FILES['upload_file']['tmp_name']) === true) {
$zip->extractTo($myPath);
}
}
I believe in your example $zip->extractTo($myPath); return false.
In your particular case it may be simpler to use system utilities to unpack the archive and then delete the files with find.
I am editing a current website right now. I want to change file uploading mechanism from http to ftp. They use File module with Drupal 7. the thing i need is, in a form, when i select which files to upload, how can i get their machine path (e.g. C:\path/to/file.mov)?
I need this path to use in php ftp_nb_put function.
function assets_managed_file_form_upload_submit($form, &$form_state) {
for ($i = 0; $i < $form_state['num_files']; $i++) {
if ($form_state['values']['files_fieldset']['managed_field'][$i] != 0) {
// Make the file permanent.
$file = file_load($form_state['values']['files_fieldset']['managed_field'][$i]);
$file->status = FILE_STATUS_PERMANENT;
$directory = 'private://cubbyhouse/'. $form_state['values']['allowed_user'];
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$file->uri = file_unmanaged_copy($file->uri, $directory, FILE_EXISTS_REPLACE);
$file->uid = $form_state['values']['allowed_user'];
drupal_chmod($file->uri);
file_save($file);
//drupal_set_message(t($debug=print_r($form)));
// Need to add an entry in the file_usage table.
file_usage_add($file, 'assets', 'image', 1);
drupal_set_message(t("Your file has been uploaded!"));
}
}
}
Right now this is how they handle file submitting
I would like to extract a zip folder to a location and to replace all files and folders except a few, how can I do this?
I currently do the following.
$backup = realpath('./backup/backup.zip');
$zip = new ZipArchive();
if ($zip->open("$backup", ZIPARCHIVE::OVERWRITE) !== TRUE) {
die ('Could not open archive');
}
$zip->extractTo('minus/');
$zip->close();
How can I put conditions in for what files and folders should NOT be replaced? It would be great if some sort of loop could be used.
Thanks all for any help
You could do something like this, I tested it and it works for me:
// make a list of all the files in the archive
$entries = array();
for ($idx = 0; $idx < $zip->numFiles; $idx++) {
$entries[] = $zip->getNameIndex($idx);
}
// remove $entries for the files you don't want to overwrite
// only extract the remaining $entries
$zip->extractTo('minus/', $entries);
This solution is based on the numFiles property and the getNameIndex method, and it works even when the archive is structured into subfolders (the entries will look like /folder/subfolder/file.ext).
Also, the extractTo method takes a second optional paramer that holds the list of files to be extracted.
If you just want to extract specific files from the archive (and you know what they are) then use the second parameter (entries).
$zip->extractTo('minus/', array('file1.ext', 'newfile2.xml'));
If you want to extract all the files that do not exist, then you can try one of the following:
$files = array();
for($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
// if $filename not in destination / or whatever the logic is then
$files[] = $filename;
}
$zip->extractTo($path, $files);
$zip->close();
You can also use $zip->getStream( $filename ) to read a stream that you then write to the destination file.