I have a folder with 5 html files. The files are called:
page-1.html
page-2.html
page-hello.html
page-32.html
yo-page-text.html
I wish to use glob function to return an array with only the files formatted: "page[number 0 - 1000]".
So essentially I wish the glob function to return the following pages from the example above:
page-1.html
page-2.html
page-32.html
This is the code that I have managed to write so far:
<?php
$directory = "testfolder/";
foreach (glob($directory . "page-*.html") as $filename) {
echo basename($filename);
}
?>
The glob pattern is not as flexible as RegEx, so unless someone has some other magic, you can filter after the glob:
$files = preg_grep('/page-[0-9]+\.html/', glob($directory . '*.*'));
If the glob pattern supported repetition + then it would be easy. Bash and Korn shells offer it with +([0-9]) but PHP doesn't.
You could also check for one number and trust that what follows matched by * will be numbers with: glob($directory . 'page-[0-9]*.html'), but this could match page-0-hello.html as well.
Assuming that your code works and that you get the basename of the files:
$name = basename($filename); //do not echo the basename
for ($i = 0; $i <= 1000; $i++) {
$trname = "page-$i";
if ($name == $trname) {
echo "$name";
}
}
Put one of these codes inside the foreach and get rid of echo basename($filename);. I'd recommend using the second one as nesting loops may prove to be a problem.
Note: This code can only work if your one works.
IMPORTANT EDIT:
My guess id that you want to do something (not echoing) the names, in which case:
function foo(bar) {
$arr = array();
$name = basename($filename);
$name = str_replace("page-", "", $name);
if (intval($name) < 1000 && intval($name) >= 0) {
$arr[] = $name;
}
}
Then, you can call on the function this way:
function foo() {
$arr = array();
$directory = "testfolder/";
foreach (glob($directory . "page-*.html") as $filename) {
$name = basename($filename);
$name = str_replace("page-", "", $name);
if (intval($name) < 1000 && intval($name) >= 0) {
$arr[] = $name;
}
}
}
$bar = foo();
foreach ($bar as $obj) {
//do something
}
Related
I need to search into folders and subfolders in search for files. In this search I need to know the files names and their path, because I have different folders and files inside of those.
I have this name 05-Navy, and inside this folder I have 3 files called 05_Navy_White_BaseColor.jpg, 05_Navy_White_Normal.jpg and 05_Navy_White_OcclusionRoughnessMetallic.jpg.
I need to only get one of them at a time because I need to add they separately to different lists.
Then I came up with the code below:
function getDirContents($dir, &$results = array()) {
$files = scandir($dir);
$findme = '_BaseColor';
$mypathCordas = null;
$findmeCordas = 'Cordas';
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
$mypathCordas = $path;
$pos = strpos($mypathCordas, $findme);
$posCordas = strpos($mypathCordas, $findmeCordas);
if (!is_dir($path)) {
if($posCordas == true){
if($pos == true){
$results[] = $path;
}
}
}
else if ($value != "." && $value != ".." ) {
if($posCordas == true){
echo "</br>";
getDirContents($path, $results);
//$results[] = $path;
}
}
}
sort( $results );
for($i = 0; $i < count($results); $i++){
echo $results[$i];
echo "</br>";
}
return $results;
}
getDirContents('scenes/Texturas');
as output result I get this: Results1
Which is not ideal at all, the biggest problem is that the list inserts the same values every time it has do add new ones, and as you can see, it doesn't sort one bit, but it shuffles. I did other things, like I have tried to use DirectoryIterator which worked really well, but I couldn't sort at all...
The printing each time something new is on the list might be my for(), but I am relatively new to php, so I can't be sure.
Also, there's this thing where it gets all the path, and I already tried using other methods but got only errors, where I would only need the scenes/texturas/ instead of the absolute path....
I'm making a search bar that searches files in a directory that have the word searched, then I want it to be added to an array by order of which one has more times the word asked to the one with less.
I'm working on PHP this is my code:
<?php
if(isset($_POST['busqueda'])){
$variable = utf8_encode($_POST['busqueda']);
}
$Array1 = array();
foreach(glob("*.txt") as $filename) {
$contents = file_get_contents($filename);
if (strpos($contents, $variable)){
$Array1[] = $filename;
}
}
I don't know how to do it exactly, I think that I should use substr_count(file_get_contents($Array1[$position1])) or something like that but I'm unsure how to make the sorting system, can someone help me!
print_r($Array1);
for($var1=0; $var1<sizeof($Array1); $var1++){
echo "times on the file: ".$Array1[$var1]."<br>";
echo substr_count(file_get_contents($Array1[$var1]));
}
?>
You can use the substr_count itself. Then you need to use arsort to sort the array.
$Array1 = array();
foreach (glob("*.txt") as $filename) {
$contents = file_get_contents($filename);
if ( ($count = substr_count($contents, $variable)) ) {
$Array1[$filename] = $count;
}
}
arsort($Array1) ;
print_r($Array1);
foreach ($Array1 as $file => $count) {
echo "times on the file($file): $count <br>";
}
Bash (available on at least Linux and Mac operating systems) makes it extremely easy to accomplish your task, because you can call commands through PHP's exec function, assuming it is not disabled by an administrator. If you're on Windows, then this will probably not work, but most people are using Linux for a production environment, so I thought this answer would be worthy of posting.
The following function is taken from CodeIgniter's file helper and only serves to fetch an array of filenames from a specified directory. If you don't need a function like this because you are getting your filenames from somewhere else, just note that this function can include the full file path for each file, and that's why I used it.
function get_filenames($source_dir, $include_path = FALSE, $_recursion = FALSE)
{
static $_filedata = array();
if ($fp = #opendir($source_dir))
{
// reset the array and make sure $source_dir has a trailing slash on the initial call
if ($_recursion === FALSE)
{
$_filedata = array();
$source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
}
while (FALSE !== ($file = readdir($fp)))
{
if (#is_dir($source_dir.$file) && strncmp($file, '.', 1) !== 0)
{
get_filenames($source_dir.$file.DIRECTORY_SEPARATOR, $include_path, TRUE);
}
elseif (strncmp($file, '.', 1) !== 0)
{
$_filedata[] = ($include_path == TRUE) ? $source_dir.$file : $file;
}
}
return $_filedata;
}
else
{
return FALSE;
}
}
Now that I can fetch an array of filenames easily, I'd do this:
/**
* Here you can see that I am searching
* all of the files in the script-library
* directory for the word "the"
*/
$searchWord = 'the';
$directory = '/var/www/htdocs/script-library';
$filenames = get_filenames(
$directory,
TRUE
);
foreach( $filenames as $file )
{
$counts[$file] = exec("tr ' ' '\n' < " . $file . " | grep " . $searchWord . " | wc -l");
}
arsort( $counts );
echo '<pre>';
print_r( $counts );
echo '</pre>';
For a good explaination of how that works, see this: https://unix.stackexchange.com/questions/2244/how-do-i-count-the-number-of-occurrences-of-a-word-in-a-text-file-with-the-comma
I tested this code locally and it works great.
I'm having trouble getting my code to work the way I want.
I'm using scandir to get all files from the directory. This gives me a list with pdf files linked to a product, but the problems comes with the posibllity of pdf files multiple languages. Like so:
1096_EN.pdf
867_PT.pdf
914_EN.pdf
914_NL.pdf
Before _ is ID and after language. And I want the user to only see one file per product.
my code looks likes this:
$files = scandir($dir);
foreach ($files as $file)
{
$exp_file = explode("_", $file);
// check file for given ID
if($exp_file[0] == $_GET['iD']){
// check file for userlanguage
if($exp_file[1] == $lang){
echo $file;
}
// check file in english
elseif($exp_file[1] == "EN"){
echo $file;
}
// return available file in other language
else{
echo $file;
}
}
}
In case of 914 and NL the code returns two files. In case of 914 and PT i only get 1 file, 914_EN.pdf and in case of 867 and NL there will be zero files.
What is the best way to filter my files and return the best matched file? I personally think the error is in the for loop, but I cant find a proper way out..
thanks
If you want to have just the single items, you should keep a backlog of which you have already processed, as the foreach loop will go from for example 914_EN.pdf to 914_NL.pdf, while the checks have already been completed for 914_EN.pdf, so when you get to 914_NL.pdf, it just reruns the checks and thinks it is okay.
if working with multiple same values, you can first cleanse the array to get what you wanted. You can take a look at this, if this what you want. Cheers!
$files = array("1096_EN.pdf", "867_PT.pdf", "914_EN.pdf", "914_NL.pdf");
$new_exp_file = array();
foreach ($files as $file) {
$exp_file = explode("_", $file);
$new_exp_file[] = $exp_file[0];
}
$new_exp_file_arr_ = array_values(array_unique($new_exp_file));
for($i = 0, $file_ctr = count($new_exp_file_arr_); $i < $file_ctr; $i++) {
if($new_exp_file_arr_[$i] == "914") {
echo $new_exp_file_arr_[$i] . "<br>";
echo "<ul>";
foreach ($files as $file) {
$exp_file = explode("_", $file);
if($new_exp_file_arr_[$i] == $exp_file[0]) {
echo "<li>" . $exp_file[1] . "</li>";
}
}
echo "</ul>";
}
}
this seems to work for me? Using a regex probably not as efficient as the above methods though.
$_GET['iD'] = 1096;
$ptn = "^((\d+)\_([a-zA-Z]+)\.([a-zA-Z]+))^";
$aFiles = array('1096_EN.pdf','867_PT.pdf','914_EN.pdf','914_NL.pdf');
$lang = "EN";
foreach ($aFiles as $sFileName)
{
preg_match($ptn, $sFileName, $aFileParts);
var_dump($aFileParts);
// check file for given ID
if($aFileParts[2] == $_GET['iD']){
// check file for userlanguage
if(strtolower($aFileParts[3]) == strtolower($lang)){
echo $sFileName;
break;
}
// return available file in other language
else{
echo $sFileName;
}
}
}
I've solved my problem by the following:
if(glob($_GET['iD']."_".$_GET['t']."*.pdf"))
{
$file = glob($_GET['iD']."_".$_GET['t']."*.pdf");
echo $file[0];
}
else
{
if(glob($_GET['iD']."_EN*.pdf"))
{
$file = glob($_GET['iD']."_EN*.pdf");
echo $file[0];
}
else
{
$file = glob($_GET['iD']."*.pdf");
echo $file[0];
}
}
No more looping, just checking for different files with wildcards. Works like a charm. I.m.o. much cleaner with larger lists of files..
I've created this code to cycle through the folders in the current directory and echo out a link to the folder, it all works fine. How would I go about using the $blacklist array as an array to hold the directory names of directories I dont want to show?
$blacklist = array('dropdown');
$results = array();
$dir = opendir("./");
while($file = readdir($dir)) {
if($file != "." && $file != "..") {
$results[] = $file;
}
}
closedir($dir);
foreach($results as $file) {
if($blocked != true) {
$fileUrl = $file;
$fileExplodedName = explode("_", $file);
$fileName = "";
$fileNameCount = count($fileExplodedName);
echo "<a href='".$fileUrl."'>";
$i = 1;
foreach($fileExplodedName as $name) {
$fileName .= $name." ";
}
echo trim($fileName);
echo "</a><br/>";
}
}
array_diff is the best tool for this job -- it's the shortest to write, very clear to read, and I would expect also the fastest.
$filesToShow = array_diff($results, $blacklist);
foreach($filesToShow as $file) {
// display the file
}
Use in_array for this.
$blocked = in_array($file, $blacklist);
Note that this is rather expensive. The runtime complexity of in_array is O(n) so don't make a large blacklist. This is actually faster, but with more "clumsy" code:
$blacklist = array('dropdown' => true);
/* ... */
$blocked = isset($blacklist[$file]);
The runtime complexity of the block check is then reduced to O(1) since the array (hashmap) is constant time on key lookup.
I have these files:
"id_1_1.php", "id_1_2.php", "id_1_3.php" etc
"id_2_1.php", "id_2_2.php", "id_2_3.php" etc
the number of files is not known because will always grow..
all the files are in same directory..
I want to make a if statement:
to include the files only if their name ends with "_1"
another function to load all the files that start with "id_1"
How can I do this? Thank you!
edit1: no the numbers will not be skipped, once I have another item for id_1_ collection of products I will add new ones as id_1_1, id_1_2 etc.. so no skipping..
// Each of these:
// - scans the directory for all files
// - checks each file
// - for each file, does it match the pattern described
// - if it does, expand the path
// - include the file once
function includeFilesBeginningWith($dir, $str) {
$files = scandir($dir);
foreach ($files as $file) {
if (strpos($file, $str) === 0) {
$path = $dir . '/' . $file;
include_once($path);
}
}
}
function includeFilesEndingWith($dir, $str) {
$files = scandir($dir);
foreach ($files as $file) {
if (strpos(strrev($file), strrev($str)) === 0) {
$path = $dir . '/' . $file;
include_once($path);
}
}
}
/* To use: - the first parameter is ".",
the current directory, you may want to
change this */
includeFilesBeginningWith('.', 'id_1');
includeFilesEndingWith('.', '_1.php');
Loosely based on Svisstack's original answer (untested):
function doIncludes($pre='',$post=''){
for ($i=1;1;$i++)
if (file_exists($str=$pre.$i.$post.'.php'))
include($str);
else
return;
}
function first_function(){
doIncludes('id_','_1');
}
function second_function(){
doIncludes('id_1_');
}
function my_include($f, $s)
{
#include_once("id_" . $f . "_" . $s . ".php");
}
function first_function($howmany = 100, $whatstart = '1')
{
for ($i=1; $i <= $howmany; $i++)
{
my_include('1', $i)
}
}
function second_function($howmany = 100, $whatend = '1')
{
for ($i=1; $i <= $howmany; $i++)
{
my_include($i, '1');
}
}
This will parse through every file incrementing by one until it finds a file that doesn't exist. Assuming contiguous numbers it should catch every existing file. If you want to include files with a number other then 1 in the name, just change $lookingfor as appropriate.
$lookingfor = 1;
$firstnum=1;
while ($firstnum>0) {
$secondnum=1;
while ($secondnum>0) {
$tempfilename = "id_".$firstnum."_".$secondnum.".php";
if file_exists($tempfilename) {
if (($firstnum==$lookingfor)||($secondnum==$lookingfor)) {include $tempfilename; }
$secondnum++;
} else {
$secondnum=-1;
}
}
$firstnum++;
}