zipArchive : how to use it - php

I have an issue with my host (and maybe my internet connection) : i use filezilla to upload several huge .zip on my website (each .zip weighs ca. 500Mo) and the connection closes before the upload's end.
So, i thought i would upload a folder containing my photographies (in that way, filezilla uploads several little files and not ONE HUGE file), and then i will make an archive of these by passing through a php script.
Here is the code i did :
/*
params :
string $nom_archive: archive's name in '.zip' (ex. 'archive.zip', 'test.zip', etc.)
string $adr_dossier: the path of the folder to archive (ex. 'images', '../dossier1/dossier2', etc.)
string $dossier_destination : path of the folder where we will copy/paste the archive (ex. 'images/zip', '../archives', etc.)
DOn't change the params $zip and $dossier_base
*/
function zipper_repertoire_recursif($nom_archive, $adr_dossier, $dossier_destination = '', $zip=null, $dossier_base = '') {
if($zip===null) {
$zip = new ZipArchive();
if($zip->open($nom_archive, ZipArchive::CREATE) !== TRUE) {
return false;
}
}
if(substr($adr_dossier, -1)!='/') {
$adr_dossier .= '/';
}
if($dossier_base=="") {
$dossier_base=$adr_dossier;
}
if(file_exists($adr_dossier)) {
if(#$dossier = opendir($adr_dossier)) {
while(false !== ($fichier = readdir($dossier))) {
if($fichier != '.' && $fichier != '..') {
if(is_dir($adr_dossier.$fichier)) {
$zip->addEmptyDir($adr_dossier.$fichier);
zipper_repertoire_recursif($nom_archive, $adr_dossier.$fichier, $dossier_destination, $zip, $dossier_base);
}
else {
$zip->addFile($adr_dossier.$fichier);
}
}
}
}
}
if($dossier_base==$adr_dossier) {
$zip->close();
if($dossier_destination!='') {
if(substr($dossier_destination, -1)!='/') {
$dossier_destination .= '/';
}
if(rename($nom_archive, $dossier_destination.$nom_archive)) {
return true;
}
else {
return false;
}
}
else {
return true;
}
}
}
And then, i call my function that way :
zipper_repertoire_recursif('Myriam&Fabien_byGFernandez_Originales.zip', './Myriam&Fabien/Photos/originales/photos_originales', './Myriam&Fabien/Photos/originales')
But it won't work, and i don't know why.
I've checked if zip is enabled on my server and it is.
DO you have any idea on my problem?
Maybe I'm using ZipArchive the wrong way, but i can't figure out what i did wrong.
COuld you help me, please?
Thank you very much.

Related

unable to delete a last file in folder while deleting folder using php

I am calling my php function from some other website which delete a folder on my server in background.
This is a function which I am using to delete a folder.
public static function remove($dir)
{
if (is_dir($dir)) {
$diropen = opendir($dir);
while($d = readdir($diropen)) {
if ($d!= '.' && $d != '..') {
self::remove($dir . "/$d");
}
}
#rmdir($dir);
} elseif (is_file($dir)) {
#unlink($dir);
}
}
If I am having three files in folder then it deletes only two and unable to delete last file or unlink fails on last file.
If I am having two files then it deletes only one file.
I have checked writable permission using is_writable it is true for all files.
Can somebody please help me out. or how to debug this behavior as this function is getting called in background.
my directory was open in some other function , so I closedir my folder and then above function working fine.
<?php
function delete_directory($target) {
if (is_dir($target))
$dir_handle = opendir($target);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle)) {
if ($file != "." && $file != "..") {
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($target.'/'.$file);
}
}
closedir($dir_handle);
rmdir($target);
return true;
}
?>
use closedir and you'll be fine.

Website Self Destruct from Browser Bar

IS there a file that I can upload onto my website (my website is a website that contains very very very sensitive information) that when navigated to in the browser (www.example.com/script.php) can be executed to delete all files from the folder it is uplaoded into/ I want to be able to delete this information easy as that. Kind of like a Self Destruct Button. MY website is used for testing sensitive equiptment commands for diamond blade cutters. We got almost the perfect cut for a diamond which makes ours very valuable. Our site was hacked and there was nothn gi could do in the backend because the password was changed on us so i want to put a secret file in there that does this.
i would not recommend that as a solution,
why don't you secure the script instead ?
anyway just for the fun of it here is a function that will delete a folder
function deleteAll($directory, $empty = false) {
$t= time(); // you can also use it to delete old files by subtracting from this
if(substr($directory,-1) == "/") {
$directory = substr($directory,0,-1);
}
if(!file_exists($directory) || !is_dir($directory)) {
return false;
} elseif(!is_readable($directory)) {
return false;
} else {
$directoryHandle = opendir($directory);
while ($contents = readdir($directoryHandle)) {
if($contents != '.' && $contents != '..') {
if(filemtime($directory . "/" . $contents) < $t) {
$path = $directory . "/" . $contents;
if(is_dir($path)) {
#deleteAll($path);
} else {
#unlink($path);
}
}
}
}
closedir($directoryHandle);
if($empty == false) {
if(!#rmdir($directory)) {
return false;
}
}
return true;
}
}
(!) be careful when you use it it will DELETE everything you can call it like this deleteAll(".", true);
but this is not a solution look into securing your script

php - extract files from folder in a zip

I have a zip file containing one folder, that contains more folders and files, like this:
myfile.zip
-firstlevel
--folder1
--folder2
--folder3
--file1
--file2
Now, I want to extract this file using PHPs ZipArchive, but without the "firstlevel" folder. At the moment, the results look like this:
destination/firstlevel/folder1
destination/firstlevel/folder2
...
The result I'd like to have would look like this:
destination/folder1
destination/folder2
...
I've tried extractTo, which produces the first mentioned result, and copy(), as suggested here, but this doesn't seem to work at all.
My current code is here:
if($zip->open('myfile.zip') === true) {
$firstlevel = $zip->getNameIndex(0);
for($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
$pos = strpos($entry, $firstlevel);
if ($pos !== false) {
$file = substr($entry, strlen($firstlevel));
if(strlen($file) > 0){
$files[] = $file;
}
}
}
//attempt 1 (extractTo):
//$zip->extractTo('./test', $files);
//attempt 2 (copy):
foreach($files as $filename){
copy('zip://'.$firstlevel.'/'.$filename, 'test/'.$filename);
}
}
How can I achieve the result I'm aiming for?
Take a look at my Quick Unzipper script. I wrote this for personal use a while back when uploading large zip files to a server. It was a backup, and 1,000s of files take forever with FTP so using a zip file was faster. I use Git and everything, but there wasn't another option for me. I place this php file in the directory I want the files to go, and put the zip file in the same directory. For my script, they all have to operate in the same directory. It was an easy way to secure it for my needs, as everything I needed was in the same dir.
Quick Unzipper: https://github.com/incomepitbull/QuickUnzipper/blob/master/unzip.php
I linked the file because I am not showcasing the repo, just the code that makes the unzip tick. With modern versions of PHP, there should't be anything that isn't included on your setup. So you shouldn't need to do any server config changes to use this.
Here is the PHP Doc for the ZipArchive class it uses: http://php.net/manual/en/class.ziparchive.php
There isn't any included way to do what you want, which is a shame. So I would unzip the file to a temp directory, then use another function to copy the contents to where you want. So when using ZipArchive, you will need to return the first item to get the folder name if it is unknown. If the folder is known, ie: the same pesky folder name every time, then you could hard code the name.
I have made it return the first item from the index. So if you ALWAYS have a zip with 1 folder inside it, and everything in that folder, this would work. However, if you have a zip file without everything consolidated inside 1 folder, it would fail. The code I have added will take care of your question. You will need to add further logic to handle alternate cases.
Also, You will still be left with the old directory from when we extract it to the temp directory for "processing". So I included code to delete it too.
NOTE: The code uses a lot of if's to show the processing steps, and print a message for testing purposes. You would need to modify it to your needs.
<?php
public function copyDirectoryContents($source, $destination, $create=false)
{
if ( ! is_dir($source) ) {
return false;
}
if ( ! is_dir($destination) && $create === true ) {
#mkdir($destination);
}
if ( is_dir($destination) ) {
$files = array_diff(scandir($source), array('.','..'));
foreach ($files as $file)
{
if ( is_dir($file) ) {
copyDirectoryContents("$source/$file", "$destination/$file");
} else {
#copy("$source/$file", "$destination/$file");
}
}
return true;
}
return false;
}
public function removeDirectory($directory, $options=array())
{
if(!isset($options['traverseSymlinks']))
$options['traverseSymlinks']=false;
$files = array_diff(scandir($directory), array('.','..'));
foreach ($files as $file)
{
if (is_dir("$directory/$file"))
{
if(!$options['traverseSymlinks'] && is_link(rtrim($file,DIRECTORY_SEPARATOR))) {
unlink("$directory/$file");
} else {
removeDirectory("$directory/$file",$options);
}
} else {
unlink("$directory/$file");
}
}
return rmdir($directory);
}
$file = dirname(__FILE__) . '/file.zip'; // full path to zip file needing extracted
$temp = dirname(__FILE__) . '/zip-temp'; // full path to temp dir to process extractions
$path = dirname(__FILE__) . '/extracted'; // full path to final destination to put the files (not the folder)
$firstDir = null; // holds the name of the first directory
$zip = new ZipArchive;
$res = $zip->open($file);
if ($res === TRUE) {
$firstDir = $zip->getNameIndex(0);
$zip->extractTo($temp);
$zip->close();
$status = "<strong>Success:</strong> '$file' extracted to '$temp'.";
} else {
$status = "<strong>Error:</strong> Could not extract '$file'.";
}
echo $status . '<br />';
if ( empty($firstDir) ) {
echo 'Error: first directory was empty!';
} else {
$firstDir = realpath($temp . '/' . $firstDir);
echo "First Directory: $firstDir <br />";
if ( is_dir($firstDir) ) {
if ( copyDirectoryContents($firstDir, $path) ) {
echo 'Directory contents copied!<br />';
if ( removeDirectory($directory) ) {
echo 'Temp directory deleted!<br />';
echo 'Done!<br />';
} else {
echo 'Error deleting temp directory!<br />';
}
} else {
echo 'Error copying directory contents!<br />';
}
} else {
echo 'Error: Could not find first directory';
}
}

Php unlink() function and cyrillic

I have a problem with deleting files through unlink() function. When the file is with a cyrillic name the function doesn't work.
[24-Jul-2012 00:33:35 UTC] PHP Warning:
unlink(/home/gtsvetan/public_html/мениджър.doc) [function.unlink]: No such file or directory
in /home/gtsvetan/public_html/deleter.php on line 114
So how to delete the file when the name is cyrillized?
The code is:
$dir = is_array($dir) ? $dir : explode(',', $dir);
foreach($dir as $dirv) {
if(is_dir($dirv)) {
$objects = scandir($dirv);
foreach($objects as $object) {
if($object != "." && $object != "..") {
if(filetype($dirv."/".$object) == "dir") {
$this->delete($dirv."/".$object);
}
else {
unlink($dirv."/".$object);
}
}
}
reset($objects);
rmdir($dirv);
}
else {
unlink($dirv);
}
}
The solution:
public function delete($dir) {
$dir = is_array($dir) ? $dir : explode(',', $dir);
foreach($dir as $dirv) {
if(is_dir($dirv)) {
$d = #dir($dirv) or die();
while(false !== ($entry = $d->read())) {
if($entry[0] == ".") {
continue;
}
if(is_dir($dirv.$entry.'/')) {
$this->delete($dirv.$entry.'/');
#rmdir($dirv.$entry);
}
elseif(is_readable($dirv.$entry)) {
#unlink($dirv.$entry);
}
}
$d->close();
}
else {
#unlink($dirv);
}
#rmdir($dirv);
}
}
And here is the ajax.php which make a instance of the class :)
case 'delete':
$location = $_POST['location'];
if(is_array($location)) {
foreach($location as $v) {
$loc[] = iconv('utf-8', 'cp1251', $v);
}
$pfm->delete($loc);
}
else {
$location = iconv('utf-8', 'cp1251', $location);
$pfm->delete($location);
}
break;
It works perfect for me :)
I'd suggest renaming it first if it not plays well.
i have found that sanitizing file names is always a good idea. personally i like to have my scripts name files itself, not users (esp if it's an uploaded file). create a cleaning function that converts cyrillic characters. take a look at convert_cyr_string :: http://php.net/manual/en/function.convert-cyr-string.php
another idea, does renaming the file have the same problem as deleting them? if not, rename it to something like tobedeleted.ext then unlink it.
unlink from PHP just forwards to the corresponding system call. The file name will be passed to that function as-is, since PHP strings are just opaque sequences of bytes. This means that the name needs to be in an encoding that the system call understands. In other words, it depends on your OS. You also need to know what is the current encoding of the file name; this depends on where the input is coming from.
If you know that the system call wants UTF-8 (which is true on Linux) and that currently the name is in ISO-8859-5, then a solution using iconv would look like
unlink(iconv('iso-8859-5', 'utf-8', $dirv."/".$object));
Of course you can do the same with mb_convert_encoding as well. The same treatment is also necessary for all the other filesystem-related calls.
Hmm, I made this, It might come in useful.
<?php
function delete($link) {
foreach($link as $u) {
if(is_dir($u)) {
delete(glob($u . DIRECTORY_SEPARATOR . "*"));
rmdir($u);
} else; unlink($u);
}
return;
}
delete(glob(__DIR__ . DIRECTORY_SEPARATOR . "*"));
?>

php ftp check if folder exists always return error creating folder

can someone please tell me what I'm doing wrong in this code?
if($id != '') {
if(is_dir("../public_html".$tem_pasta['path']."/pics/".$id)) {
echo "pasta já existia";
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$id."/".$myFileName;
} else {
//pasta nao existia
if (ftp_mkdir($conn_id, "../public_html".$tem_pasta['path']."/pics/".$id)) {
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$id."/".$myFileName;
//echo "pasta criada<br>";
} else {
echo "erro, não criou a pasta<br>";
}
}
} else {
$destination_file = "../public_html".$tem_pasta['path']."/pics/".$myFileName;
}
it checks if I've a folder ($id) within my pics directory, and if not the script creates a new one.
works good, but if I try to upload another file to the previous created folder it does return an error, saying it didn't create the folder...
thanks
I don't think you can use is_dir on a FTP resource, what you should do is check if the size of the dir/file is -1 with ftp_size.
Because I think what now happens is: you are trying to make the same folder again, and this is why a error occurs.
Edit:
Or check with ftp_chdir!
<?php
function ftp_directory_exists($ftp, $dir)
{
// Get the current working directory
$origin = ftp_pwd($ftp);
// Attempt to change directory, suppress errors
if (#ftp_chdir($ftp, $dir))
{
// If the directory exists, set back to origin
ftp_chdir($ftp, $origin);
return true;
}
// Directory does not exist
return false;
}
?>
Should work!
is_dir works only on the local file-system. If you want to check if a ftp-directory already exists try this:
function ftp_is_dir($ftp, $dir)
{
$pushd = ftp_pwd($ftp);
if ($pushd !== false && #ftp_chdir($ftp, $dir))
{
ftp_chdir($ftp, $pushd);
return true;
}
return false;
}
if($id != '') {
if(ftp_is_dir($conn_id, "../public_html".$tem_pasta['path']."/pics/".$id)) {
// and so on...
Use ftp_nlist and in_array
$ftp_files = #ftp_nlist($this->connection, $directory);
if ($ftp_files === false) {
throw new Exception('Unable to list files. Check directory exists: ' . $directory);
}
if (!in_array($directory, $ftp_files)) {
$ftp_mkdir = #ftp_mkdir($this->connection, $directory);
if ($ftp_mkdir === false) {
throw new Exception('Unable to create directory: ' . $directory);
}
}
With PHP 8.0 (on AWS) the solution with #ftp_chdir() does not hide the error and causes the program to stop. The solution with ftp_nlist() doesn't give good results because it returns either false if the path doesn't exist or an element if the path is a file or a list if it's a directory but doesn't give the "." and ".." elements that would identify a directory.
The ftp_mlsd() function seemed more convenient: it returns a list, possibly empty, only if the path is a directory, false otherwise. But it doesn't work correctly on all servers!
Finally it is the ftp_rawlist() function which seems to be the most generalized because it launches a LIST command on the server and returns the result. If the path is a directory we have an array, possibly empty and we have the value false if it is not a directory.
$list = ftp_rawlist( $ftp_conn, $remote_path );
$is_dir = is_array( $list );

Categories