Randomly select a file from directory in PHP - php

So I have seen solutions of this, however my question is slightly different.
I want the file to have a character at the end.
So, for example, there is a directory called imgs:
imgs
contents: div.png, div2.png, divb.png, divab.png
I need to randomly select a file from this folder, but I need it to have a b at the end. So I could only get on either divb.png or divab.png.
If I get one that doesn't end in b, I need to reselect.
I currently have some code that gives me a timeout and doesn't reselect.
function random_pic($dir = 'imgs'){
$files = glob($dir . '/*.png');
$file = array_rand($files);
if(substr($files[$file], -5)==$shortparam.".png"){
return $files[$file];
} else {
return null;
}
}
EDIT -----------------
<?php
function random_pic() {
$files = glob('imgs/*.png' );
do {
if ( isset( $file ) ) {
unset( $files[$file] );
}
$file = array_rand( $files );
} while ( ( substr( $files[ $file ], -5 != ( $shortparam . ".png" ) ) ) AND ( count( $files) > 0 ) );
if ( count( $files ) > 0 ) {
return $files[ $file ];
} else {
echo $file;
return false;
}
}
for ($i = 0 ; $i < 20; $k++){
$image = random_pic();
if($image == false){
} else {
// display image
This times out for some reason.
(Fatal error: Maximum execution time of 10 seconds exceeded in file.php on line 84)
Thanks for any help you can give!

You could achieve that with a blend of glob, array_walk(), array_rand() and preg_match().
<?php
function random_pic($dir='imgs', $extension=".png", $endChar="b"){
$files = glob($dir . "/*{$extension}");
$matches = array();
array_walk($files, function($imgFile, $index) use ($extension, $endChar, &$matches) {
$pixName = preg_replace("#" . preg_quote($extension) . "#", "", basename($imgFile));
if( preg_match("#" . preg_quote($endChar) . "$#", $pixName)){
$matches[] = $imgFile;
}
});
return (count($matches))? $matches[array_rand($matches)] : null;
}
$randomPic = random_pic(__DIR__. "/imgs", ".png", "b");
// OR JUST USE THE DEFAULTS SINCE THEY ARE JUST THE SAME IN YOUR CASE:
// $randomPic = random_pic();
var_dump($randomPic);

I obviously don't have your files and your directory structure to try this code against, but I'm pretty confident it will solve your problem.
function random_pic( $dir = 'imgs' ) {
if ( $files = glob( $dir . '/*.png' ) ) {
do {
if ( isset( $file ) ) {
unset( $files[$file] );
}
if ( count( $files ) > 0 ) {
$file = array_rand( $files );
}
} while ( ( substr( $files[ $file ], -5 != ( $shortparam . ".png" ) ) ) AND ( count( $files ) > 0 ) );
if ( count( $files ) > 0 ) {
return $files[ $file ];
} else {
return NULL;
}
} else {
return NULL;
}
}
You may want to consider returning FALSE instead of NULL if nothing is found since it's more versatile on the parent end.

Related

How to resolve "Parse error: syntax error" in PHP? [duplicate]

This question already has answers here:
PHP parse/syntax errors; and how to solve them
(20 answers)
Closed 5 years ago.
I try many solution but it does help.i try even to switch on short_tags_on but no solution.
I am getting this error:
Parse error: syntax error, unexpected end of file in
C:\xampp\htdocs\photo_gallery\includes\functions.php on line 76
Here is my code, what is wrong?
<?php
function strip_zeros_from_date( $marked_string="" ) {
// first remove the marked zeros
$no_zeros = str_replace('*0', '', $marked_string);
// then remove any remaining marks
$cleaned_string = str_replace('*', '', $no_zeros);
return $cleaned_string;
}
function redirect_to( $location = NULL ) {
if ($location != NULL) {
header("Location: {$location}");
exit;
}
}
function output_message($message="") {
if (!empty($message)) {
return "<p class=\"message\">{$message}</p>";
} else {
return "";
}
}
function __autoload($class_name) {
$class_name = strtolower($class_name);
$path = LIB_PATH.DS."{$class_name}.php";
if(file_exists($path)) {
require_once($path);
} else {
die("The file {$class_name}.php could not be found.");
}
}
function include_layout( $names, $args ){
// allow for single file names
if ( !is_array( $names ) ) {
$names = array( $names );
}
$found = false;
foreach ( $names as $name ) {
$file = siteroot.'/public/layouts/'.$name.'.php';
if ( file_exists( $file ) ) {
$found = $file;
break;
}
}
if ( ! $found ) {
return '';
}
function log_action($action, $message="") {
$logfile = SITE_ROOT.DS.'logs'.DS.'log.txt';
$new = file_exists($logfile) ? false : true;
if($handle = fopen($logfile, 'a')) { // append
$timestamp = strftime("%Y-%m-%d %H:%M:%S", time());
$content = "{$timestamp} | {$action}: {$message}\n";
fwrite($handle, $content);
fclose($handle);
if($new) { chmod($logfile, 0755); }
} else {
echo "Could not open log file for writing.";
}
}
function datetime_to_text($datetime="") {
$unixdatetime = strtotime($datetime);
return strftime("%B %d, %Y at %I:%M %p", $unixdatetime);
}
?>
I am using xampp on Windows 7. I have been trying to find a solution but I dont know what wrong. Since I added the function method of including the header.php and footer.php it start giving me that error. Here is the method that I add:
function include_layout( $names, $args ){
// allow for single file names
if ( !is_array( $names ) ) {
$names = array( $names );
}
$found = false;
foreach ( $names as $name ) {
$file = siteroot.'/public/layouts/'.$name.'.php';
if ( file_exists( $file ) ) {
$found = $file;
break;
}
}
if ( ! $found ) {
return '';
}
You're not closing the include_layout function, it's missing a final }.
function include_layout( $names, $args ){
// allow for single file names
if ( !is_array( $names ) ) {
$names = array( $names );
}
$found = false;
foreach ( $names as $name ) {
$file = siteroot.'/public/layouts/'.$name.'.php';
if ( file_exists( $file ) ) {
$found = $file;
break;
}
}
if ( ! $found ) {
return '';
}
} // << missing from your code

counter in a php recursive function

I've looked thru the questions already with the system, but couldn't find the answer to my problem. I want to try a counter in a php recursive function, which looks for and deletes empty folders. I paste below a way to echo non-empties as "–" and empties as "|". It looks ok after all, but in case there's a lot to purge, it all grows into gibberish on the screen. Instead I'd like to see the numbers of folders checked vs deleted. Here's the code compiled so far using StackOverflow too. Any help pls?
function RemoveEmptySubFolders($path) {
echo "–";
$empty = true;
foreach ( glob ( $path . DIRECTORY_SEPARATOR . "*" ) as $file ) {
if (is_dir ( $file )) {
if (! RemoveEmptySubFolders ( $file ))
$empty = false;
} else {
$empty = false;
}
}
if ($empty) {
if (is_dir ( $path )) {
// echo "Removing $path...<br>";
rmdir ( $path );
echo "|";
}
}
return $empty;
}
Just pass the variables as reference:
function recursive($path, &$directories, &$removed) {
echo "-";
$directories ++;
$empty = true;
foreach ( glob ( $path . DIRECTORY_SEPARATOR . "*" ) as $file ) {
if (is_dir ( $file )) {
if (! recursive ( $file, $directories, $removed ))
$empty = false;
} else {
$empty = false;
}
}
if ($empty) {
if (is_dir ( $path )) {
$removed++;
echo "|";
}
}
return $empty;
}
$path = "c:\exampledir";
$directories = 0;
$removed = 0;
recursive($path, $directories, $removed);
echo("<br>$directories, $removed");
You could also use global variables, but that's very ugly, and every time you use a global variable othen than the standard ones, a kitty dies.
Object-Oriented variant:
Put everything in a class and add the instance attributes $checked and $deleted, then increment them with a selfmade procedure or (nasty code) just with += 1 or $var ++.

Recursion through a directory tree in PHP

I have a set of folders that has a depth of at least 4 or 5 levels. I'm looking to recurse through the directory tree as deep as it goes, and iterate over every file. I've gotten the code to go down into the first sets of subdirectories, but no deeper, and I'm not sure why. Any ideas?
$count = 0;
$dir = "/Applications/MAMP/htdocs/site.com";
function recurseDirs($main, $count){
$dir = "/Applications/MAMP/htdocs/site.com";
$dirHandle = opendir($main);
echo "here";
while($file = readdir($dirHandle)){
if(is_dir($file) && $file != '.' && $file != '..'){
echo "isdir";
recurseDirs($file);
}
else{
$count++;
echo "$count: filename: $file in $dir/$main \n<br />";
}
}
}
recurseDirs($dir, $count);
Check out the new RecursiveDirectoryIterator.
It's still far from perfect as you can't order the search results and other things, but to simply get a list of files, it's fine.
There are simple examples to get you started in the manual like this one:
<?php
$path = realpath('/etc');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
echo "$name\n";
}
?>
There is an error in the call
recurseDirs($file);
and in
is_dir($file)
you have to give the full path:
recurseDirs($main . '/' .$file, $count);
and
is_dir($main . '/' .$file)
However, like other anwerers, I suggest to use RecursiveDirectoryIteretor.
The call to is_dir and recurseDirs is not fully correct. Also your counting didn't work correctly. This works for me:
$dir = "/usr/";
function recurseDirs($main, $count=0){
$dirHandle = opendir($main);
while($file = readdir($dirHandle)){
if(is_dir($main.$file."/") && $file != '.' && $file != '..'){
echo "Directory {$file}: <br />";
$count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting
}
else{
$count++;
echo "$count: filename: $file in $main \n<br />";
}
}
return $count;
}
$number_of_files = recurseDirs($dir);
Notice the changed calls to the function above and the new return value of the function.
So yeah: Today I was being lazy and Googled for a cookie cutter solution to a recursive directory listing and came across this. As I ended up writing my own function (as to why I even spent the time to Google for this is beyond me - I always seem to feel the need to re-invent the wheel for no suitable reason) I felt inclined to share my take on this.
While there are opinions for and against the use of RecursiveDirectoryIterator, I'll simply post my take on a simple recursive directory function and avoid the politics of chiming in on RecursiveDirectoryIterator.
Here it is:
function recursiveDirectoryList( $root )
{
/*
* this next conditional isn't required for the code to function, but I
* did not want double directory separators in the resulting array values
* if a trailing directory separator was provided in the root path;
* this seemed an efficient manner to remedy said problem easily...
*/
if( substr( $root, -1 ) === DIRECTORY_SEPARATOR )
{
$root = substr( $root, 0, strlen( $root ) - 1 );
}
if( ! is_dir( $root ) ) return array();
$files = array();
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$sub_files = recursiveDirectoryList(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
$files = array_merge( $files, $sub_files );
}
else
{
$files[] = $root . DIRECTORY_SEPARATOR . $entry;
}
}
return (array) $files;
}
With this function, the answer as to obtaining a file count is simple:
$dirpath = '/your/directory/path/goes/here/';
$files = recursiveDirectoryList( $dirpath );
$number_of_files = sizeof( $files );
But, if you don't want the overhead of an array of the respective file paths - or simply don't need it - there is no need to pass a count to the recursive function as was recommended.
One could simple amend my original function to perform the counting as such:
function recursiveDirectoryListC( $root )
{
$count = 0;
if( ! is_dir( $root ) ) return (int) $count;
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$count += recursiveDirectoryListC(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
}
else
{
$count++;
}
}
return (int) $count;
}
In both of these functions the opendir() function should really be wrapped in a conditional in the event that the directory is not readable or another error occurs. Make sure to do so correctly:
if( ( $dir_handle = opendir( $dir ) ) !== false )
{
/* perform directory read logic */
}
else
{
/* do something on failure */
}
Hope this helps someone...

How to delete a folder in which was started as a script?

I have a delete.php in folder abc so I call localhost/abc/delete.php. I want to be able to delete abc folder and all its contents from server when I call localhost/abc/delete.php. How to do such thing?
This function deletes a directory with
all of it's content. Second parameter
is boolean to instruct the function if
it should remove the directory or only
the content
function rmdir_r ( $dir, $DeleteMe = TRUE )
{
if ( ! $dh = #opendir ( $dir ) ) return;
while ( false !== ( $obj = readdir ( $dh ) ) )
{
if ( $obj == '.' || $obj == '..') continue;
if ( ! #unlink ( $dir . '/' . $obj ) ) rmdir_r ( $dir . '/' . $obj, true );
}
closedir ( $dh );
if ( $DeleteMe )
{
#rmdir ( $dir );
}
}
//use like this:
rmdir_r( 'abc' );
http://www.roscripts.com/snippets/show/170
Try something like this:
function deleteDir($dir) {
if (!is_dir($dir)) return unlink($dir);
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
if (!deleteDir($dir.'/'.$item)) return false;
}
return rmdir($dir);
}
$dir = substr($_SERVER['SCRIPT_FILENAME'], 0, strrpos($_SERVER['SCRIPT_FILENAME'], '/'));
deleteDir($dir);

Get the hierarchy of a directory with PHP

I'm trying to find all the files and folders under a specified directory
For example I have /home/user/stuff
I want to return
/home/user/stuff/folder1/image1.jpg
/home/user/stuff/folder1/image2.jpg
/home/user/stuff/folder2/subfolder1/image1.jpg
/home/user/stuff/image1.jpg
Hopefully that makes sense!
function dir_contents_recursive($dir) {
// open handler for the directory
$iter = new DirectoryIterator($dir);
foreach( $iter as $item ) {
// make sure you don't try to access the current dir or the parent
if ($item != '.' && $item != '..') {
if( $item->isDir() ) {
// call the function on the folder
dir_contents_recursive("$dir/$item");
} else {
// print files
echo $dir . "/" .$item->getFilename() . "<br>";
}
}
}
}
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $f) {
echo "$f \r\n";
}
The working solution (change with your folder name)
<?php
$path = realpath('yourfolder/subfolder');
## or use like this
## $path = '/home/user/stuff/folder1';
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename)
{
echo "$filename\n";
}
?>
$dir = "/home/user/stuff/";
$scan = scandir($dir);
foreach ($scan as $output) {
echo "$output" . "<br />";
}
Find all the files and folders under a specified directory.
function getDirRecursive($dir, &$output = []) {
$scandir = scandir($dir);
foreach ($scandir as $a => $name) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $name);
if (!is_dir($path)) {
$output[] = $path;
} else if ($name != "." && $name != "..") {
getDirRecursive($path, $output);
$output[] = $path;
}
}
return $output;
}
var_dump(getDirRecursive('/home/user/stuff'));
Output (example) :
array (size=4)
0 => string '/home/user/stuff/folder1/image1.jpg' (length=35)
1 => string '/home/user/stuff/folder1/image2.jpg' (length=35)
2 => string '/home/user/stuff/folder2/subfolder1/image1.jpg' (length=46)
3 => string '/home/user/stuff/image1.jpg' (length=27)
listAllFiles( '../cooktail/' ); //send directory path to get the all files and floder of root dir
function listAllFiles( $strDir ) {
$dir = new DirectoryIterator( $strDir );
foreach( $dir as $fileinfo ) {
if( $fileinfo == '.' || $fileinfo == '..' ) continue;
if( $fileinfo->isDir() ) {
listAllFiles( "$strDir/$fileinfo" );
}
echo $fileinfo->getFilename() . "<br/>";
}
}
Beside RecursiveDirectoryIterator solution there is also glob() solution:
// do some extra filtering here, if necessary
function recurse( $item ) {
return is_dir( $item ) ? array_map( 'recurse', glob( "$item/*" ) ) : $item;
};
// array_walk_recursive: any key that holds an array will not be passed to the function.
array_walk_recursive( ( recurse( 'home/user/stuff' ) ), function( $item ) { print_r( $item ); } );
You can use the RecursiveDirectoryIterator or even the glob function.
Alternatively, the scandir function will do the job.

Categories