Preg_match help : selecting files in a folder - php

I have the following code that selects all the different template files out of a folder... The file names I have are:
template_default.php
template_default_load.php
template_sub.php
template_sub_load.php
I only want to select the ones without the _load in the file name so I used this code:
preg_match('/^template_(.*)[^[_load]]{0}\.php$/i', $layout_file, $layout_name)
The code works fine except it cuts the last character off the result... Instead of returning default or sub when I echo $layout_name[1], it shows defaul and su...
Any ideas what is wrong with my code?

This part is totally up the creek:
[^[_load]]{0}
This is the regex you want:
/^template_(.*)(?<!_load)\.php$/i

You'll have to use negative assertions. (read below why not)
preg_match('/^template_(.*?)(?!_load)\.php$/i', $layout_file, $layout_name)
Edit: come to think of it, that regexp won't actually work because "_load" will be consumed by the .*? part. My advice: don't use preg_match() to capture the name, use it to skip those that end with _load, e.g.
foreach (glob('template_*') as $filepath)
{
if (preg_match('#_load\\.php$', $filepath))
{
// The file ends with _load
}
$filename = basename($filepath);
$layout_name = substr($filename, strlen('template_'));
}

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.

PHP: Searching for an exact string pattern in array elements

I want to validate all the files that are being uploaded on my site through PHP. I am using regular expressions to compare the file contents but it doesn't seem to be working as I expect it to work. I want to accept files with 1 term per line only.
EXPECTED INPUT:
HP34930
HP09099
HP98899
UNACCEPTABLE INPUT:
HP89980 HP98798 HP09232
some other text
HP58089
Here is my code:
$texthandle = file($_FILES["textfile"]["tmp_name"]);
foreach ($texthandle as $textline)
{
if (!preg_match("/(HP\d+){1}/", $textline))
{
echo "Incorrect file format. Please provide a text file with 1 term per line.";
exit(0);
}
}
Could someone suggest why this isn't detecting the way I want it to?
I have also tried
if (!preg_match("/^(HP\d+){1}$/", $textline))
but it isn't working as I expect it to work.
Thanks for your help!
Not sure what not working is, but try:
$texthandle = file($_FILES["textfile"]["tmp_name"], FILE_IGNORE_NEW_LINES);
and then:
if (!preg_match("/^HP\d+$/", $textline))
or if there are only 5 digits allowed:
if (!preg_match("/^HP[\d]{5}$/", $textline))
If there is any whitespace at the end like spaces, tabs, etc. it will fail, so you can try trim() on $textline.

using substring to add word to string

Not sure if the title for this is correct but here's my problem:
I have a table that hold image's url like so:
img/folder/imagename.jpg
Now I've created a thumbnail for each image in each folder, so if I want to display them I do a loop in my table and return all the url's but I need to add the word "thumbs" after "folder/" and before the "imagename.jpg"...Now because obviously the "folder" and "imagename" names differ in length then I can't do a count..the only thing I can figure is to look up that last "/" character and insert there and add on the "imagename.jpg" after it so end result would look like:
img/folder/thumbs/imagename.jpg
Just replace the path with a "deeper" path:
$path = str_replace('img/folder/', 'img/folder/thumbs/', $path);
There are lots of other ways to do this, but IMHO this one is perfectly clear on what it does. Theoretically it won't work universally (if your path contains multiple occurreces of img/folder/ for some reason), but let's just not go there.
you can also
$pathparts = explode("/",$path);
and then use $pathparts array to construct your path again. You would use it in cases you want to have more control over manipulating paths, but in heavy loads it's not very efficient.
echo $pathparts[0]."/".$pathparts[1]."/thumbs/".$pathparts[2];
//adition
And why not to update your database and script only save imagename.jpg
and then in the beginning of calling script define
define("IMGPATH", "img/folder/");
define("THUMBPATH", "img/folder/thumbs/");
and then call it
<?= IMGPATH."imagename.jpg" ?>
<?= THUMBPATH."imagename.jpg" ?>

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.

Why is fopen() behaving like this?

I am currently working on this project which requires me to make a function which dinamically decides the directory name and then creates a simple .txt file in that directory.
my code is as follows:
($destinatario is a string)
$diretorio="../messages/".$destinatario;
if (is_dir($diretorio)) {
;
}else{
mkdir($diretorio);
}
$path=$diretorio."/".$data.",".$assunto.",".$remetente.".txt";
$handle=fopen($path,'w+');
fwrite($handle, $corpo);
fclose($handle);
nevermind the portuguese, but the bottom line is that it should create a .txt file using the naming guidelines i've provided. The funny thing is that when i do this, php creates this weird file whose filename is "01.09.2010 04"
(with no extension at all) which amounts to the first few characters of the actual filename i'd like to create...
edit($data is actually the output from a call to date("d.m.Y H:i"))
Per comment by OP:
[$data is] actually the output of a call to date("d.m.Y H:i")
The problem is the : character. (Still, there may be other illegal characters in the other parts composing the final file name.)
EDIT
The essence of the problem and solution is in the comments to #tchen's answer. Keep in mind that colon is a valid file name character on (some? all?) *nix platforms but is invalid on Windows.
Make sure there's no bad characters at the end of $data. Call trim() on it.
If it's data taken from a file, it may have a '\r' or '\n' at the end of it.
Not related, but make sure your if statements don't have unused conditions:
if (!is_dir($diretorio)) {
mkdir($diretorio);
}
This will also get rid of that blank line with a single terminator ;, I'm sure that isn't right.
Some ideas:
have you tried not using commas in the filename?
Have you checked the return value if fopen and fwrite?
Just to try to isolate the problem
also you can simplify to:
if (!is_dir($diretorio)) {
mkdir($diretorio);
}

Categories