Does glob() have negation? - php

I know I can do this...
glob('/dir/somewhere/*.zip');
...to get all files ending in .zip, but is there a way to return all files that are not ZIPs?
Or should I just iterate through and filter off ones with that extension?

You could always try something like this:
$all = glob('/dir/somewhere/*.*');
$zip = glob('/dir/somewhere/*.zip');
$remaining = array_diff($all, $zip);
Although, using one of the other methods Pascal mentioned might be more efficient.

A quick way would be to glob() for everything and use preg_grep() to filter out the files that you do not want.
preg_grep('#\.zip$#', glob('/dir/somewhere/*'), PREG_GREP_INVERT)
Also see Glob Patterns for File Matching in PHP

This pattern will work:
glob('/dir/somewhere/*.{?,??,[!z][!i][!p]*}', GLOB_BRACE);
which finds everything in /dir/somewhere/ ending in a dot followed by either
one character (?)
or two characters (??)
or anything not starting with the consecutive letter z,i,p ([!z][!i][!p]*)

I don't think glob can do a "not-wildcard"...
I see at least two other solutions :
use a combinaison of opendir / readdir / closedir
Or use some SPL Iterator ; To be more specific, I'm thinking about DirectoryIterator ; and maybe you can combine it with some FilterIterator ?

$dir = "/path";
if (is_dir($dir)) {
if ($d = opendir($dir)) {
while (($file = readdir($d)) !== false) {
if ( substr($file, -3, 3) != "zip" ){
echo "filename: $file \n";
}
}
closedir($d);
}
}
NB: "." and ".." not taken care of. Left for OP to complete

Related

how to exclude a certain folder when using scandir in php

I am using scandir to list all the files in a directory. But there should be an exception for ./, ../ and tmp folder.
I already have this to exclude the dot and double dot:
$files = preg_grep('/^([^.])/', scandir($dir));
How can i add tmp folder to it? (name of the folder is tmp)
I would choose for this solution, because of already mentioned by #duskwuff, your current code excludes all the files which start with a .
$files = array_diff( scandir($dir), array(".", "..", "tmp") );
Try :
$toRemove = array('.','..','tmp');
$cdir = scandir($dir);
$result = array_diff($cdir, $toRemove);
It's easier than preg_grep
Since it's a regex you can try to take a look at the negative lookahead:
$files = preg_grep('/^(?!tmp|\.{1,2})$/', scandir($dir));
I would have done something like that if you want to stick with regex
$files = preg_grep('/^(?!tmp|(?!([^.]))).*/', scandir($dir));

How to prevent words containing certain letters from being echoed out in PHP?

What happens here is that all the files in the directory are retrieved and then echoed out onto the page through PHP. The files contained in $blacklist are the ones that are not echoed out.
However, how could I change this so that if the file name (that is to be echoed out) contains the letters .txt all together in a row at the end of the word, it is then put into the blacklist so that it's not echoed out.
Does this make any sense?
<?php
$blacklist = array("one.jps", "two.txt", "four.html" , ".txt");
$files = array_diff(glob("*.*"), $blacklist);
foreach($files as $file)
echo "<div class='post'><a href='" . $_SERVER['PHP_SELF'] . "?file=" . $file . "'><p>" . $file . "</p></a></div>";
if(!empty($_GET["file"]) && !in_array($_GET["file"], $blacklist) && file_exists($_GET["file"]))
$thesource = htmlentities(file_get_contents($_GET["file"]));
?>
Assuming you want to keep $blacklist for further usage:
$blacklist = preg_grep("/\b.txt\b/", $files);
foreach (array_diff($files, $blacklist) as $whiteListedFile) {
// do your things
}
preg_grep is what you need here. Keep in mind that the example above will blacklists "file.txt" but not "file.txts" or "file.stxt" . Adjust the pattern for your needs. This is a good online regex tester for PHP.
You can use a regular expression. Haven't played with the syntax, so you will have to work on that.
preg_match('.txt', $string)
http://php.net/manual/en/function.preg-match.php

correct regex date pattern for dd/mm/yyyy

I need to update the same line, which is also including a date in dd/mm/yyyy format along with some string, in a group of files. I have checked answers here given to similar questions however couldn’t make any of the patterns suggested run in my code.
My current PHP code is:
<?php
// get the system date
$sysdate = date("d/m/Y");
// open the directory
$dir = opendir($argv[1]);
$files = array();
// sorts the files alphabetically
while (($file = readdir($dir)) !== false) {
$files[] = $file;
}
closedir($dir);
sort($files);
// for each ordered file will run the in the clauses part
foreach ($files as $file) {
$lines = '';
// filename extension is '.hql'
if (strpos($file,".hql") != false || strpos($file,".HQL") != false)
{
$procfile = $argv[1] . '\\' . $file;
echo "Converting filename: " . $procfile . "\n";
$handle = fopen($procfile, "r");
$lines = fread($handle, filesize($procfile));
fclose($handle);
$string = $lines;
// What are we going to change runs in here
$pattern = '[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]';
$replacement = $sysdate;
$lines = preg_replace($pattern, $replacement, $string);
echo $lines;
$newhandle = fopen($procfile, 'w+');
fwrite($newhandle, $lines);
fclose($newhandle);
// DONE
}
}
closedir($dir);
?>
When I run this code on command prompt, it doesn’t give any error message and it seems to be running properly. But once it finishes and I check my files, I see that the content of each file is getting deleted and they all become 0 KB files with nothing in them.
You have no delimiters set in place for your regular expression.
A delimiter can be any (non-alphanumeric, non-backslash, non-whitespace) character.
You want to use a delimiter besides / so you avoid having to escape / already in your pattern.
You could use the following to change your format:
$pattern = '~[0-9]{4}/[0-9]{2}/[0-9]{2}~';
See Live demo
This one also do basic checks (month between 1-12, day between 1-31)
(0(?!0)|[1-2]|3(?=[0-1]))\d\/(0(?!0)|1(?=[0-2]))\d\/\d{4}
See it live: http://regex101.com/r/jG9nD5
You should surround the regular expression with delimiter character.
For example:
$pattern = '![0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]!';
/ is commonly used, but because the regular expression contains / itself, I used ! instead.
Besides the lack of delimiters (# and ~ are favorites, if / is used in the pattern), you are looking for 4 digits at the beginning: yyyy/mm/dd. Decide what you're looking for. You might also be able to do something like
[0-9]{4}/[0-9]{2}/[0-9]{2}
or even
\d{4}/\d{2}/\d{2}
... I know those will work in Perl, but I haven't tried them with PHP (they ought to work, as the "p" in preg stands for Perl, but no guarantees).
Why use regex? Use DateTime class for validation.
var_dump(validateDate('2012-02-28', 'Y-m-d')); # true
var_dump(validateDate('28/02/2012', 'd/m/Y')); # true
var_dump(validateDate('30/02/2012', 'd/m/Y')); # false
function
Your code can be rewritten in short like this:
#!/usr/bin/php
<?php
// get the system date
$sysdate = date('d/m/Y');
// change working directory to the specified one
chdir($argv[1]);
// loop over the *.hql files in sorted order
foreach (glob('*.{hql,HQL}', GLOB_BRACE) as $file) {
echo "Converting filename: $argv[1]\\$file\n";
$contents = file_get_contents($file);
$contents = preg_replace('#\d{4}/\d{2}/\d{2}#', $sysdate, $contents);
echo $contents;
file_put_contents($file, $contents);
}
The problem was with the missing PCRE regex delimiters as others already pointed out. Even after fixing this, the code was not really nice.
The glob and file_get_contents functions are available as of PHP 4.3.0. The file_put_contents function is available as of PHP 5.
glob makes your code more succinct, readable and even portable as you won‘t have to mention directory separator anywhere except the info message. You used \\ but should have used DIRECTORY_SEPARATOR if you wanted your code to be portable.
The file_get_contents function fetches the whole contents of a file as a string. The file_put_contents function does the opposite – stores a string in a file. If you want it in PHP 4, use this implementation:
if (!function_exists('file_put_contents')):
function file_put_contents($filename, $data) {
$handle = fopen($filename, 'w');
$result = fwrite($handle, $data);
fclose($handle);
return $result;
}
endif;
Also notice that the final ?> is not necessary in PHP.

PHP regular expression for directory

I need a regular expression that would take the string after the last forward slash.
For example, considering I have the following string:
C:/dir/file.txt
I need to take only the file.txt part (string).
Thank you :)
You don't need a regex.
$string = "C:/dir/file.txt";
$filetemp = explode("/",$string);
$file = end($filetemp);
Edited because I remember the latest PHP spitting errors out about chaining these types of functions.
If your strings are always paths you should consider the basename() function.
Example:
$string = 'C:/dir/file.txt';
$file = basename($string);
Otherwise, the other answers are great!
The strrpos() function finds the last occurrence of a string. You can use it to figure out where the file name starts.
$path = 'C:/dir/file.txt';
$pos = strrpos($path, '/');
$file = substr($path, $pos + 1);
echo $file;

Remove all dots in filename except the dot before the file extension

I am trying to sanitize a filename.
I would like to know of a way to remove all decimals from a files name except the last one. I need to keep the last one because the extension follows that.
EXAMPLE:
abc.def.ghij-klmnop.q234.mp3
This file should look like
abcdefghij-klmnopq234.mp3
Some extensions are longer than 3 characters.
You can use a regex with a positive lookahead. Like this:
$withdots = 'abc.def.ghij-klmnop.q234.mp3';
$nodots = preg_replace('/\.(?=.*\.)/', '', $withdots);
After executing the above, $nodots will contain abcdefghij-klmnopq234.mp3. The regular expression is basically saying match all periods that are followed by another period. So the last period won't match. We replace all matches with an empty string, and we're left with the desired result.
That should do it:
$file = 'abc.def.ghij-klmnop.q234.mp3';
$parts = pathinfo($file);
$filename = str_replace('.', '', $parts['filename']).'.'.$parts['extension'];
You could also do this, it should be faster then using pathinfo & str_replace.
$parts = explode('.', 'abc.def.ghij-klmnop.q234.mp3');
$ext = array_pop($parts);
$nodots = implode('', $parts) . '.' . $ext;
Assuming $s is the name of the file.
$s = (($i = strrpos($s, '.')) === false) ? $s :
str_replace('.','',substr($s,0,$i)).substr($s,$i);

Categories