What is wrong with this regex PHP code? - php

I have a folder that stores some thousands of pictures files.
I want to change the name of each file that matches the condition.
The idea is if the file name has _10 change to _ten, if has _5 change to _five.
So, xxdf23_10hy.jpg should be xxdf23_tenhy.jpg, 16_5_gt5.jpg should change to 16_five_gt5.jpg. But if file mane is gdjd_7.jpg, do nothing.
The code is working good, but it is matching the string ".." that should not be matched.
This is the part of the code:
$photoPath="../pic/";
$dir = new DirectoryIterator($photoPath);
foreach ($dir as $fileinfo) {
$filename = $fileinfo->getFilename();
if(preg_match($filename, "/_10/")){
//change te name to "_ten"
}
elseif(preg_match($filename, "/_5/")){
//change te name to "_five"
}
}
Something is not good with the way I am using the preg_match function.
But if I try it inside regex tester it works good.
What am I missing?

You've got your subject and pattern switched in the preg_match() commands. Try this:
if (preg_match("/_10/", $filename)) {
// more code
}
http://php.net/manual/en/function.preg-match.php

No need for the overhead of regex here at all. Perhaps simple glob() and str_replace() would meet your needs.
$photoPath="../pic/";
$replacements = array(
'_5' => '_five',
'_10' => '_ten'
);
foreach ($replacements as $pattern => $replace) {
$files = glob($photoPath . '*' . $pattern . '*');
foreach($files as $file) {
$old_name = $file;
$new_name = str_replace($pattern, $replace, $old_name);
rename($old_name, $new_name);
}
}
Here we don't even use regex or PHP string searching functionality to find the files we want to change. We use glob() which is basically a direct call to underlying libc glob() function and should perform significantly better and with less memory usage than the DirectoryIterator with post-filter functionality you are currently using. DirectoryIterator is probably overkill here anyway unless you are doing more complex file operations. glob() would filter your file names for you, meaning you are not doing useless regex searches against every file contained in DirectoryIterator object like you are currently doing.
The actual filepath name change is executed using basic str_replace(). You don't currently show how you are doing this, but I would imagine you would implement something similar or possibly just use preg_replace() rather than preg_match() if you desire to stick with regex approach.

Related

php __FILE__ inside includes?

I have (maybe) an unusual issue with using __FILE__ in a file within a file.
I created a snippet of code (in the php 5 my server mandates) to take elements of the current filename and put it into a variable to use later. After some headache, I got it working totally fine. However, I realized I didn't want to have to write it every time and realized "oh no, if I include this it's only going to work on the literal filename of the include". If I wanted to grab the filename of the page the user is looking at, as opposed to the literal name of the included file, what's the best approach? Grab the URL from the address bar? Use a different magic variable?
EDIT1: Example
I probably should have provided an example in the first draft, pfft. Say I have numbered files, and the header where the include takes place in is 01header.php, but the file it's displayed in is Article0018.html. I used:
$bn = (int) filter_var(__FILE__, FILTER_SANITIZE_NUMBER_INT);
…to get the article number, but realized it would get the 1 in the header instead.
EDIT2: Temporary Solution
I've """solved""" the issue by creating a function to get the URL / URI and putting it into the variable $infile, and replaced all former appearances of __FILE__ with $infile, like so:
function getAddress() {
$protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
return $protocol.'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];}
$infile = urlencode(getAddress());
$bn = (int) filter_var($infile, FILTER_SANITIZE_NUMBER_INT);
echo "$bn";
So if the file the user is looking at is called "005-extremelynormalfile.html", I can display the number 5 inside the page, e.g., to say it's article number five.
While it's not as bad as I initially thought based on your description your code is still very fragile, and really only works by accident. If you have any other digits or hyphens it's going to go wrong, as below.
$infile = 'https://example-123.com/foo/42/bar/005-extremelynormalfile.html?x=8&y=9';
var_dump(
filter_var($infile, FILTER_SANITIZE_NUMBER_INT),
(int)filter_var($infile, FILTER_SANITIZE_NUMBER_INT)
);
Output:
string(12) "-12342005-89"
int(-12342005)
Sanitize functions are a blunt instrument for destroying data, and should only ever be used as a last resort when all other good sense has failed.
You need to use a proper parsing function to parse the url into its component parts, and then a simple regular expression to get what you want out of the filename.
function getIdFromURL($url) {
$url_parts = parse_url($url);
$path = $url_parts['path'];
$path_parts = explode('/', $path);
$filename = end($path_parts);
if( preg_match('/^(\d+)/', $filename, $matches) ) {
return (int)$matches[1];
}
return null;
}
var_dump(
getIdFromURL($infile)
);
Lastly, a lot of people are tempted to cram as much logic as possible into a regular expression. If I wanted to the above could be a single regex, but it would also be rigid, unreadable, and unmaintainable. Use regular expressions sparingly, as there's nearly always a parser/library that already does what you want, or the majority of it.
Quickly threw together a function that gets the url from the page as a variable, and replaced all occurrences of __FILE__ with that variable, and it worked correctly. Assuming the user cannot edit the URL / URI in any way, this should work well enough.

Retrieve and tidy up one directory name in a url. e.g. I need example.com/main/this_dir/page.html to output as "This Dir"

I am stuggling to comprehend how to accomplish the following task "
From : http://www.example.com/main/this_dir/page.html
I would like an output of : This Dir
When using $_SERVER['REQUEST_URI'] i can get this output :
*/main/this_dir/*
I would like to now take that and strip the last string between the two /'s so i end up with
*this_dir*
I would then like to take that string and turn it into
This Dir
There is a slight complication with this too because the directory could simply be called /this/ and not /this_dir/, but it is always one or the other and the text does change whereas the words i used were merely an example.
If anyone has any suggestions, input or feedback as to how i could accomplish this task it would be greatly appreciated! I do have a vague idea of how i could strip the last directory name from the request_uri string but i would really like to know if it would even be possible to transform the string in the way that i have described, using PHP.
You can use the basename function to get the "this_dir" part, so then it's simply a case of doing something like this:
$directoryName = ucwords(str_replace('_', ' ', basename($_SERVER['REQUEST_URI'])));
Edit
Slightly more convoluted example that will work for pages such as "/main/this_dir/something.php":
$directoryName = ucwords(str_replace('_', ' ', basename(substr($_SERVER['REQUEST_URI'], 0, strrpos($_SERVER['REQUEST_URI'], '/')))));
This is just stripping anything after the final "/" before passing to basename to ensure it'll work as before. Note that this will NOT work though for URLs without a trailing "/" such as "/main/this_dir" - in this case it would output "Main".
$path = explode("/", dirname($_SERVER['REQUEST_URI']));
$directory = end($path);
This should give you the last directory in the path.
Then you can do:
$dirParts = explode("_", $directory);
$dirName = implode(" ", array_map("ucfirst", $dirParts));
To get the directory name in a user-friendly format.
Edit: In fact, as RobMaster said, it is probably easier to do ucwords(str_replace("_", " ", $directory))

Edit filepath PHP

I have a delete button on my page, that delete button has to delete a certain entry in my database (not too difficult), it has to delete the entire folder where the file that holds the delete button is in (also doable), but I also want it to delete another folder that's placed somewhere else and I'm not sure how to do that. Using
dirname(__FILE__);
I am able to get the filepath where the file holding the delete button is located. That results in this:
mywebsite.nl/subdomains/dongen/httpdocs/s-gravenmoer/aandrijvingenenbesturingen/logo4life
The filepath that I also want to delete is quite similair, but a little different. The last 3 folders a variable, so their lenght (in characters) is always different. However, the second to last folder has to be deleted from this filepath so this remains:
mywebsite.nl/subdomains/dongen/httpdocs/s-gravenmoer/logo4life
Is there a way to do this with PHP? Using substr or something like that perhaps?
Thanks!
I think this should do the trick:
$folderToRemove = preg_replace( '#^(.*)/(.*?)/(.*?)$#', "$1/$3", dirname(__FILE__) );
You can try using "glob." Details in www.php.net/glob
You can try:
$files = glob('subdomains/dongen/httpdocs/*/logo4life');
foreach ($files as $file) {
unlink($file); // note that this is very dangerous though, you may end up deleting a lot of files
}
You don't need anything fancy, as you guessed, a simple str_replace will do it:-
$file = 'mywebsite.nl/subdomains/dongen/httpdocs/s-gravenmoer/aandrijvingenenbesturingen/logo4life';
var_dump(str_replace('aandrijvingenenbesturingen/', '', $file));
Output:-
string 'mywebsite.nl/subdomains/dongen/httpdocs/s-gravenmoer/logo4life' (length=62)
$path = "mywebsite.nl/subdomains/dongen/httpdocs/s-gravenmoer/aandrijvingenenbesturingen/logo4life";
$regex = "/(.*\/).*\/(.*)/";
$matches = array();
preg_match($regex, $path, $matches);
// var_dump($matches);
$new_path = $matches[1].$matches[2];
echo $new_path;
Above code uses preg_match for matching a regexp in a string.

How to add wildcard names to directory search in php

I've got a small php script that will gather all files in a directory. Futhermore, I'm cleaning through this array of names to skip over the ones I don't want:
$dirname = "./_images/border/";
$border_images = scandir($dirname);
$ignore = Array(".", "..");
foreach($border_images as $border){
if(!in_array($border, $ignore)) echo "TEST".$border;
}
This directory would contain images that I want to find. Amongst these images, there will be a thumbnail version and a full-size version of each image. I'm planning to have each image either labeled *-thumbnail or *-full to more easily sort through.
What I'm trying to find is a way to, preferably with the $ignore array, add a wildcard string that will be recognized by a check condition. For example, adding *-full in my $ignore array would make that files with this tag, anywhere in their filenames, would be ignored. I'm pretty sure the in_array wouldn't accept this. If this isn't possible, would using regular expressions be possible? If so, what would my expression be?
Thanks.
You're probably looking for php's function glob()
$files_full = glob('*-full.*');
There is a better way to do this known as glob().
Take a look at glob function.
glob — Find pathnames matching a pattern

basic question in foreach in php

basically if I have a string like this:
$str = \data1\data2\data3\data_tmp\file.pgp
can anyone tell me how to get the last part 'file.pgp'?
TIA.
You are looking for the basename() function.
This function takes a file path and returns the file name without the suffix (the final part of your file name that specifies its type)
$last = array_pop(explode('\\', $str));
You don't need foreach for that. It's used when you have to iterate through the whole collection (in your case, array).
If you need to get the remaining part of the string:
$segments = explode('\\', $str);
$last = array_pop($segments);
It will be in $segments, as an array. If you want to convert it back to a string, then use join('\\', $segments). However, if this is a Windows path and you're running PHP on Windows, then you should be using the basename and dirname functions.
perhaps pathinfo() will give you what you need
if that doesn't do it try
$path = str_replace('\\', '/', $path)
first

Categories