Reputation: 173
I want to search for a specific string inside a zip file, "Plugin Name" / "Theme Name" inside a file contents. But the problem is some zip files contain child zip files. How do I perform a search inside all zip files included child zip files and get the string and parent zip path?
Zip 1:
-folder
-folder
-phpfile.php
Zip 2:
-Child zip
-Child zip
-folder
-folder
-phpfile
-style.css
-Child zip
I want to find the Theme Name inside the style.css for example.
Style.css contain:
/*
Theme Name: Twenty Twenty
Theme URI: https://wordpress.org/themes/twentytwenty/
Author: the WordPress team
Author URI: https://wordpress.org/
Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor. Organizations and businesses have the ability to create dynamic landing pages with endless layouts using the group and column blocks. The centered content column and fine-tuned typography also makes it perfect for traditional blogs. Complete editor styles give you a good idea of what your content will look like, even before you publish. You can give your site a personal touch by changing the background colors and the accent color in the Customizer. The colors of all elements on your site are automatically calculated based on the colors you pick, ensuring a high, accessible color contrast for your visitors.
Tags: blog, one-column, custom-background, custom-colors, custom-logo, custom-menu, editor-style, featured-images, footer-widgets, full-width-template, rtl-language-support, sticky-post, theme-options, threaded-comments, translation-ready, block-styles, wide-blocks, accessibility-ready
Version: 1.3
Requires at least: 5.0
Tested up to: 5.4
Requires PHP: 7.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: twentytwenty
This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned with others.
*/
Code example:
$search='Plugin Name';
$replace=' --BRIGHT YELLOW HIPPOPOTAMUS-- ';
function modifyzip($archive,$search,$replace)
{
$zip = new ZipArchive();
$status = $zip->open( $archive );
if( $status == true ){
/* Get the count of files BEFORE the loop */
$filecount = $zip->numFiles;
for( $i=0; $i < $filecount; $i++ ){
$name = $zip->getNameIndex( $i );
$content = $zip->getFromName( $name );
$edited = str_replace( $search, $replace, $content );
$zip->deleteName( $name );
$zip->addFromString( $name, $edited );
}
}
$zip->close();
}
$dir=DIR . '/zips/';
$col=glob( $dir . '*.zip' );
if( $col && count( $col ) > 0 ){
foreach( $col as $archive ){
call_user_func( 'modifyzip',$archive,$search,$replace );
}
}
But it will replace a string
Also this way can read a php file but it won't help so much because need to find a specific string inside all contents:
$zip = new ZipArchive;
if ($zip->open('test1.zip') === TRUE) {
echo $zip->getFromName('testfromfile.php');
$zip->close();
} else {
echo 'failed';
}
I am new to PHP so I ask for help.
EDIT:
I have tried the code on WAMP (Localhost, Windows 10)
$path = getcwd()."/files";
$object = new PhpDirectoryIterator();
$object->addModifier("css", function ($path) {
if(strpos(file_get_contents($path), "Theme Name: ") !== false) {
$explodedPath = explode('/', $path);
$fileName = end($explodedPath);
echo "Found it in : " . $fileName;
}
}
);
Failed with this error:
Warning: scandir(C:\wamp64\www\ziptest/files/actionable-google-analytics-woocommerce.zip301a8ba5a9b4cb56eb47debf7ceda1da,C:\wamp64\www\ziptest/files/actionable-google-analytics-woocommerce.zip301a8ba5a9b4cb56eb47debf7ceda1da): The system cannot find the file specified. (code: 2) in C:\wamp64\www\ziptest\index2.php on line 24
I have a folder with ZIP Files which i want to make the search
Upvotes: 2
Views: 459
Reputation: 1944
Hi
Your question was nice for me and i think about it one day and write the code for solving this problem in general :)
We want to have an iterator that give a path and modifier and itrate the all files in the path recursively and modify the some specific file and we said to it
We make a function exec
that get the path and change the file that we mention in our modifier and if it see a directory in the path is send its data to the exec
again (call is recursively) and is see the zip file extracted it and name it in special way (because when you want to zip this extracted file again you need to know that was a extracted directory and you need to know the original name too) and again go throw it
$files = $this->fileManager->getFileNamesInPath($path);
foreach ($files as $fileName) {
$extension = $this->nameManager->getFileExtentionFromFileName($fileName);
if ($this->nameManager->isZipFile($extension)) {
$tempExtractedDirectoryName = $this->nameManager->getTempExtractedDirectoryName($fileName);
$this->fileManager->unzip($path, $fileName ,$tempExtractedDirectoryName);
$this->exec($this->nameManager->getAbsolutePathWithDirectory($path, $tempExtractedDirectoryName));
}
if ($this->nameManager->isDirectory($extension)) {
$this->exec($this->nameManager->getAbsolutePathWithDirectory($path, $fileName));
}
foreach ($this->modifiers as $modifierExtention => $modifierFunction) {
if ($extension == $modifierExtention) {
$modifierFunction($this->nameManager->getAbsolutePathWithDirectory($path, $fileName));
}
}
}
After that we check the directory name and if we are in the extracted directory we zip it and replace it with the old zip file and then remove the old zip file
$folderName = $this->nameManager->getCurrectDirectoryNameFromAbsolutePath($path);
if ($this->isExtentedDirectory($folderName)) {
$zipFileName = $this->getZipFileNameFromExtendedDirectoryName($folderName);
$zipFilePath = $this->getZipFilePath($path, $folderName);
$this->fileManager->remove($zipFilePath . $zipFileName);
$this->fileManager->zip($zipFilePath, $zipFileName, $folderName);
$this->fileManager->remove($path);
}
So with this work exec
function iterate all files in the path
recursively and do what you want in the files that you say in your modifier
You can do what you want in the files with modifier
For example is you want to add one line to the test file you should to sth like this and use the addModifier
function:
$path = getcwd();
$object = new PhpDirectoryIterator();
$object->addModifier("txt", function ($path) {
$myfile = fopen($path, "a") or die("Unable to open file!");
$txt = "test\n";
fwrite($myfile, $txt);
fclose($myfile);
}
);
$object->exec($path);
.
├── a.txt
├── b.txt
├── main.php
├── test
│ └── c.txt
└── test.zip
They are my files
a.txt , b.txt and c.txt are empty text files
And there is a d.txt in the test.zip which is a empty text file
And that is main.php file
<?php
class PhpFileManager
{
public function unzip($dir, $zipFileNamem ,$destonationName)
{
exec("cd $dir && unzip $zipFileNamem -d $destonationName");
}
public function remove($path)
{
exec("rm -rf $path");
}
public function zip($path, $zipFileName ,$foldername)
{
exec("cd $path$foldername && zip -r ../$zipFileName .");
}
public function getFileNamesInPath($path)
{
return array_diff(scandir($path), ['.','..']);
}
}
class PhpNameManager
{
const ZIP_EXTENTION = 'zip';
const ZIP_EXTENTION_WITH_DOT = '.zip';
const DITECTORY_EXTENTION = '';
const HASH_ALGORITHM = 'md5';
public function getFileExtentionFromFileName($fileName)
{
$explodedFileName = explode('.', $fileName);
if (count($explodedFileName) == 1) {
return '';
}
return end($explodedFileName);
}
public function getTempExtractedDirectoryName($fileName)
{
return $fileName . $this->hash($fileName);
}
public function hash($text)
{
return hash(self::HASH_ALGORITHM, $text);
}
public function getAbsolutePathWithDirectory($path, $directory)
{
return $path . '/' . $directory;
}
public function getCurrectDirectoryNameFromAbsolutePath($path)
{
$explodedPath = explode('/', $path);
return end($explodedPath);
}
public function isZipFile($extension)
{
if ($extension == self::ZIP_EXTENTION) {
return true;
}
return false;
}
public function isDirectory($extension)
{
if ($extension == self::DITECTORY_EXTENTION) {
return true;
}
return false;
}
}
class PhpDirectoryIterator
{
private $fileManager;
private $nameManager;
private $modifiers = [];
public function __construct()
{
$this->fileManager = new PhpFileManager;
$this->nameManager = new PhpNameManager;
}
public function addModifier($extension, $clouusre)
{
$this->modifiers[$extension] = $clouusre;
}
public function exec(string $path)
{
$files = $this->fileManager->getFileNamesInPath($path);
foreach ($files as $fileName) {
$extension = $this->nameManager->getFileExtentionFromFileName($fileName);
if ($this->nameManager->isZipFile($extension)) {
$tempExtractedDirectoryName = $this->nameManager->getTempExtractedDirectoryName($fileName);
$this->fileManager->unzip($path, $fileName ,$tempExtractedDirectoryName);
$this->exec($this->nameManager->getAbsolutePathWithDirectory($path, $tempExtractedDirectoryName));
}
if ($this->nameManager->isDirectory($extension)) {
$this->exec($this->nameManager->getAbsolutePathWithDirectory($path, $fileName));
}
foreach ($this->modifiers as $modifierExtention => $modifierFunction) {
if ($extension == $modifierExtention) {
$modifierFunction($this->nameManager->getAbsolutePathWithDirectory($path, $fileName));
}
}
}
$folderName = $this->nameManager->getCurrectDirectoryNameFromAbsolutePath($path);
if ($this->isExtentedDirectory($folderName)) {
$zipFileName = $this->getZipFileNameFromExtendedDirectoryName($folderName);
$zipFilePath = $this->getZipFilePath($path, $folderName);
$this->fileManager->remove($zipFilePath . $zipFileName);
$this->fileManager->zip($zipFilePath, $zipFileName, $folderName);
$this->fileManager->remove($path);
}
}
public function isExtentedDirectory($DirectoryName)
{
$explodedDirectoryName = explode(PhpNameManager::ZIP_EXTENTION_WITH_DOT, $DirectoryName);
if (count($explodedDirectoryName) == 2) {
$directoryName = $explodedDirectoryName[0] . PhpNameManager::ZIP_EXTENTION_WITH_DOT;
$directoryHashedName = $explodedDirectoryName[1];
if ($directoryHashedName == $this->nameManager->hash($directoryName)) {
return true;
}
}
return false;
}
public function getZipFileNameFromExtendedDirectoryName($extentedDirectoryName)
{
$explodeDirectoryName = explode(PhpNameManager::ZIP_EXTENTION_WITH_DOT, $extentedDirectoryName);
return reset($explodeDirectoryName) . PhpNameManager::ZIP_EXTENTION_WITH_DOT;
}
public function getZipFilePath($dir, $folderName)
{
return str_replace($folderName, '', $dir);
}
}
$path = getcwd();
$object = new PhpDirectoryIterator();
$object->addModifier("txt", function ($path) {
$myfile = fopen($path, "a") or die("Unable to open file!");
$txt = "test\n";
fwrite($myfile, $txt);
fclose($myfile);
}
);
$object->exec($path);
?>
(I separate the works that are related to the file and which are related to the namings in two classes and it should work in the Unix-based distributions and you have problem with the rm
, zip
, unzip
functions in your device you can just change these functions in the fileManager class)
If you run the php code this code will added one line to all of the text files (in the directory and in the zip files too)
You should see some things like it in all text files
test
If you have any questions feel free to ask and thanks for your good question
For example if you want to search for the special string in the all files you can do it
$path = getcwd();
$object = new PhpDirectoryIterator();
$object->addModifier("txt", function ($path) {
if(strpos(file_get_contents($path), "Theme Name : ") !== false) {
$explodedPath = explode('/', $path);
$fileName = end($explodedPath);
echo "Found it in : " . $fileName;
}
}
);
$object->exec($path);
Upvotes: 3