PHP function 'scandir' not working on WordPress hosted on windows - php

When i am using scandir function i get different results on linux and windows.
Windows i see only folder name
Linux it does the job under
I run a check if WordPress files has been changed ?
function find_all_files($dir, $deep)
{
if(strpos($dir,"wp-content") == false){
$root = scandir($dir);
foreach($root as $value)
{
if($value === '.' || $value === '..') {continue;}
if(is_file("$dir/$value")) {
$tmpFile = "$dir/$value";
if(5000000>#filesize($tmpFile)){
$result[]="$tmpFile";
}
continue;
}
$tmp = "$dir/$value";
if(strpos($tmp,"wp-content") == false){
if($deep == true){
foreach(#$this->find_all_files("$dir/$value",true) as $value)
{
$tmpFile = $value;
if(5000000>#filesize($tmpFile)){
$result[]="$tmpFile";
}
}
}
}
}
//var_dump($result);
return $result;
}
}

I had a similar issue and it all came down to:
1) if you mean "running on windows" OS you need to include, and start from the drive directory (where server is installed) in $dir to scan.
2) Windows might be picky about separators, compare your $dir with Wordpress ABSPATH and try to use PHP constant DIRECTORY_SEPARATOR instead of your own '/' separators.
3) And I asume you working with paths, not urls (http://localhost/wordpress/...plugin/dir/). This is working for me on Windows 7, running Uniserver (LAMP):
$rootfolder = 'startfolder';
$dir = plugin_dir_path(dirname( __FILE__ )).DIRECTORY_SEPARATOR.$rootfolder;
$files = array_slice(scandir($dir), 2);
However, you need to cut down the path end begin in the install dir with ABSPATH or something. But I recommend to test where your filescript is, like plugins folder, to not consume a huge stall on errors while working with this kind of stuff.
Hint!
The PHP docs about scandir has a lot off contributed functions about reading, retriving, scanning functions and issues. Take a look at: http://php.net/manual/en/function.scandir.php
Important!
Do not start messing with windows folder access, and if you do, take a RAW copy of whole www directory first, otherwise exported Worpdress installs could get messy on a Apache server live.
Remember, did you manage to install a new plugin from the Wordpress
admin, you propably dont have a folder access issue.
Hop this helps!

Related

How do I keep the most recent OPcache folder only?

I'm new to using OPcache on php 8 and I have some questions. So my folder structure looks like this:
https://i.stack.imgur.com/vb93u.png
Within each folder is the exact same thing, it's the structure of my website.
Why does OPcache generate multiple folders with the same content?
What is the best way to keep only the most recent folder and delete the others? Is there a check that can be done every so often or a setting that overwrites older files with new ones?
I'm fast approaching the file limit with my hosting and need to clear up some space.
I've read the docs but I don't have a lot of knowledge working with servers so any help is greatly appreciated!
Oh and these are the settings in my php.ini:
zend_extension=opcache.so;
opcache.enable=1;
opcache.memory_consumption=32;
opcache.interned_strings_buffer=8;
opcache.max_accelerated_files=3000;
opcache.revalidate_freq=180;
opcache.fast_shutdown=0;
opcache.enable_cli=0;
opcache.revalidate_path=0;
opcache.validate_timestamps=1;
opcache.max_file_size=0;
opcache.file_cache=/mywebsitepath/.opcache;
opcache.file_cache_only=1;
Just in case anyone else has the same problem, this is what I ended up doing. First I tried to use the Wordpress cron manager but I was having issues getting a simple function to work. Instead, in my hosting you can create a cron job and link it to a php file, so I went that route instead. Here's the contents of the cron-jobs.php file which I put in my OPcache folder. Basically it sorts the folders by date modified then deletes the old ones while keeping the fresh one. If anyone has suggestions for improvements, be my guest!
function opcache_clean($dir) {
$folders = array();
foreach (scandir($dir) as $file) {
//we only want the folders, not files
if ( strpos($file, '.') === false ) {
$folders[$file] = filemtime($dir . '/' . $file);
}
}
//only delete the old folders if there is more than one
if (count($folders) > 1) {
arsort($folders);
$folders = array_keys($folders);
//keep the first folder (most recent directory at index 0)
$deletions = array_slice($folders, 1);
foreach($deletions as $delete) {
echo "deleting $delete <br>";
system("rm -rf ".escapeshellarg($delete));
}
}
else {
echo "No folders to delete!";
}
}
//clean the current directory
opcache_clean ( dirname(__FILE__) );

PHP is_dir() doesn't work when nested

Here is my folder structure:
main
- folder_1
-- folder_1_1
-- folder_1_2
-- folder_1_3
- folder_2
-- folder_2_1
-- folder_2_2
-- folder_2_3
And here is my code:
<?php
$mainfolder ="main";
function readDirs($mainfolder){
if(hasSubFolder($mainfolder)){
echo("$mainfolder HAS sub folder");
}else{
echo("$mainfolder DOESN'T HAVE sub folder");
}
}
function hasSubFolder($folder){
$newPath="";
if (is_dir($folder)) {
echo ("$folder IS a folder</br>");
$handle = opendir($folder);
while (false !== ($entry = readdir($handle))) {
$newPath = $folder."\\".$entry;
if (is_dir($newPath)){
echo "$newPath IS a folder</br>";
} else {
echo "$newPath IS NOT a folder</br>";
}
}
}
}
readDirs($mainfolder);
?>
And this is what I get:
main IS a folder
main\. is NOT a folder
main\.. is NOT a folder
main\folder_1 is NOT a folder
main\folder_2 is NOT a folder
main DOESN'T HAVE sub folder
So I'd like to know why "if (is_dir($newPath))" doesn't return true even $newPath is a folder/dir. Is it because it's nested inside another another is_dir()?
Thank
Since PHP can run on a multitude of platforms, which might use even more exotic directory separators than forward or backward slash, there's a beautiful system constant defined you can used instead: DIRECTORY_SEPARATOR.
It automatically contains the right separator for the current host OS, such as the backslash for Windows or the forward slash for a *nix system. You can then use:
$newPath = $folder.DIRECTORY_SEPARATOR.$entry;
This is always better than hardcoding it for any OS as the other answer suggests.
Currently, for backwards compatibility reasons, PHP internally always does a str_replace from / to DIRECTORY_SEPARATOR within its internal file functions, but this is not guaranteed to keep working forever - it costs performance and isn't strictly needed.
Linux uses / for folder separation, and Windows does too. It's only DOS that doesn't. Replace \\ with / and you should be good to go.

Scan file or folder with bad permissions

I'd just like to see a list of files and folders where folder <> 755 and file <> 644
Is there a script that can recursively scan all files/folders on my web server for this info?
My site got hacked, a bunch of files were set to 200 permissions, its a Joomla 1.5 site, so many files/folders, will take for ever to do this manually.
Host at 1and1 and is a linux shared server
I'm looking for a PHP script
SOLUTION (thanks Robert for info)
For some reason on windows and linux folders return 55
I got the function for perms from http://php.net/manual/en/function.fileperms.php
<?php
$path = realpath('.');
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),RecursiveIteratorIterator::SELF_FIRST);
$c = 0;
foreach($files as $name => $f){
$perm = file_perms($f);
if ($perm!="644" && $perm!="755" && $perm!="55") {
$c++;
echo "<b>".$perm."</b> :: ";
echo $f->getPathname()."<br>";
if ($c==200) {exit();}
}
}
function file_perms($file, $octal = false)
{
if(!file_exists($file)) return false;
$perms = fileperms($file);
$cut = $octal ? 2 : 3;
return substr(decoct($perms), $cut);
}
?>
You can use php with chmod() function and resursive directory iterator
To check file permissions you can use fileperms() function. It returns the file's permissions as a numeric mode. You can use resursive directory iterator + this checking with fileperms() and you can set permissions with chmod(). With Directory Iterator you can also use getPerms() method.
Example:
$path = realpath('/path/to/dic');
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),RecursiveIteratorIterator::SELF_FIRST);
foreach($files as $name => $f){
if($f->getPerms() != 775 && $f->isFile()) {
chmod($fileinfo->getPathname(), 0775);
echo getPathname();
}
}
This will set chmod to 775 for files that have different permissions. You can also use 3 methods to check read/write/exec permmisions:
DirectoryIterator::isExecutable() - Determine if current DirectoryIterator item is executable
DirectoryIterator::isReadable() - Determine if current DirectoryIterator item can be read
DirectoryIterator::isWritable() - Determine if current DirectoryIterator item can be written to
You should upgrade to more recent Joomla! version as soon as possible. Otherwise, you'll face more and more successful attacks in the future, because Joomla! 1.5 has reached EOL (end of life) a long time ago.
Generally it is a good idea to use a tool like Akeeba Admin Tools, which can do exactly what you asked for, and a lot of other useful stuff to harden your Jommla! installation.
find /home/*/public_html -type d -perm 755

PHP Iterating through and removing directory issues

I've built a system whereby users can start a project and upload files to this project. When they create the project, I create a directory specifically for that project and all uploads fill this directory. However, I have implemented a system that allows the user to remove this project if they wish, deleting all the files within the directory and then the directory itself.
Locally (on MAMP), this worked a charm; on a live server however, it doesn't. For the directory removal I used a stock piece of code from a tutorial website (posted below) and as I said, works fine on a local webserver.
$name = $_POST['projectName'];
rrmdir("../../project/$name");
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir."/".$object) == "dir") rrmdir($dir."/".$object); else unlink($dir."/".$object);
}
}
reset($objects);
rmdir($dir);
echo "Directory Removed";
}
Be very careful with this:
$name = $_POST['projectName'];
rrmdir("../../project/$name");
That's like an SQL injection for your server's file system, imagine if someone types this in to their browser: http://www.yoursite.com/this-script.php?projectName=../../../../var/www You'll probably want to look at escapeshellarg() to help close this gaping security hole and realpath() to convert the relative path in to an absolute one. If the target dir isn't empty then rmdir won't work, you need to remove all of the subdirs and files first before rmdir will work.
Try this one instead:
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('/path/to/project/directory'),
RecursiveIteratorIterator::CHILD_FIRST);
foreach($iterator as $fileObject) {
if($fileObject->isFile()) {
echo 'Removing File: ', $fileObject->getRealpath(), PHP_EOL;
// unlink($fileObject->getRealpath());
} elseif($fileObject->isDir()) {
echo 'Removing Dir: ', $fileObject->getRealpath(), PHP_EOL;
// rmdir($fileObject->getRealpath());
}
}
Uncomment the rmdir and unlink lines to actually perform the removals.
Noticing your use of relative paths please see if this comment helps:
http://php.net/manual/en/function.unlink.php#85938

Moving a file to the Recycle Bin (PHP)

This question is related to a Windows install of PHP5.
Doing a file unlink() makes it difficult for recovery.
Instead I would like to move the file to the Recycle Bin (without doing an exec()).
Do you have any idea?
Thanks for your help.
This is the only solution that works and it's portable in all drives.
function Recycle($filename)
{
if (is_file($filename) === true)
{
$filename = realpath($filename);
$recycle = glob(current(explode('\\', $filename, 2)) . '\\RECYCLER\\*', GLOB_ONLYDIR);
if (is_array($recycle) === true)
{
return rename($filename, current($recycle) '\\' . basename($filename));
}
}
return false;
}
Deleted files are correctly moved to for instance:
O:\RECYCLER\S-1-5-21-1715567821-1390067357-1417001333-1003
Restore from the Recycle Bin should be possible, however I've not tested it.
EDIT: I just updated this function to work with files that have relative paths.
why dont you just create one folder and name it "Recycle Bin" .. then instead of doing an unlink() .. just move the files to this "Recycle Bin" folder??
If you wish to move a file, use the rename() php function.
Then later you can run a cron script which checks the time of the files and then you can delete files, say, older than 10 days etc.
I hope this helps.
This works for me, using MaDdoGs CmdUtils, under Win7 x64, php 5.4.24. Also with large files, odd filenames, ...
function recycle($filename)
{
if ( !is_file($filename) )
return false;
system( __DIR__.'/third-party/Recycle.exe -f "'.$filename.'"', $r );
return $r;
}

Categories