So I have created a basic code to upload images. The user uploads 2 images and when they are being processed/uploaded I have a small bit of code to make sure that file names aren't the same when they get uploaded to the server
if(file_exists($imgpath1)){
$imgpath1 = $imgpath1 . $random;
}
if(file_exists($imgpath2)){
$imgpath2 = $imgpath2 . $random;
}
Let's say $imgpath1 = "images/user/1.jpg" to begin with (before the PHP above is ran)
and $random is a random number generated at the start of the script, lets say $random = '255'.
The code works perfectly, and the images still display correctly, but it is adding the '255' ($random) directly to the end of the filepath, so $imgpath1 = "images/user/1.jpg255" after the code above has ran.
The file extension won't always be .jpg obviously, it could be .png, .bmp and so on...
How can I make the $random (255 in this instance) go before the ".jpg" in the filepath? I have tried researching on google but I can't seem to word it correctly to find any useful answers.
Thanks
You can try this code :
$filename = "file.jpg";
$append = "001";
function append_filename($filename, $append) {
preg_match ("#^(.*)\.(.+?)$#", $filename , $matches);
return $matches[1].$append.'.'.$matches[2];
}
echo append_filename($filename, $append);
It gives : file001.jpg
http://www.tehplayground.com/#JFiiRpjBX (Ctrl+ENTER for test)
You could do it like this:
This will extract the path and filename before the last period ($regs[1]) and the rest until the end of the string ($regs[2]).
if (preg_match('/^(.*)\.([^.].*)$/i', $imgpath1, $regs)) {
$myfilename = $regs[1] . $random . $regs[2];
} else
$myfilename = $imgpath1;
}
Works with file filenames like /path/subpath/filename.jpg or /path/subpath/filename.saved.jpg, etc.
What the Regex means:
# ^(.*)\.([^.].*)$
#
# Assert position at the beginning of the string «^»
# Match the regular expression below and capture its match into backreference number 1 «(.*)»
# Match any single character that is not a line break character «.*»
# Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
# Match the character “.” literally «\.»
# Match the regular expression below and capture its match into backreference number 2 «([^.].*)»
# Match any character that is NOT a “.” «[^.]»
# Match any single character that is not a line break character «.*»
# Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
# Assert position at the end of the string (or before the line break at the end of the string, if any) «$»
You can use pathinfo function to get the required aprts, and rebuild with the random part added:
if(file_exists($imgpath1)){
$pathinfo = pathinfo($imgpath1);
$imgpath1 = $pathinfo['dirname'] .'/' . $pathinfo['filename'] . $random . '.' . $pathinfo['extension'];
}
Though your $random variable will need to be a unique id, else you can still get collisions.
You will also need to filter out bad chars (people on different filesystems to your server etc). Often its just easier to replace the whole name with uniqid() . '.' . $pathinfo['extension'];
Related
I have a string with a wildcard at the end, but I don't know how many characters that string will be. How can I use GlobIterator and RegexIterator to match similar file names? The second match returns all the files from a directory, but I don't want that. I need a proper regular expression. I don't want to match the last set before the extension (ex. the files sized 250M, 500M, etc.)
$iterator = new GlobIterator($this->srcDir . $identifier . ".*");
MATCH ON
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.*
This returns the correct files.
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.250m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.500m.jpg
MATCH ON
/var/www/import/2014047-0216/YukonGold.A2014047.1620.*
Returns the files:
/var/www/import/2014047-0216/YukonGold.A2014047.1620.250m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.500m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.250m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.500m.jpg
EXPECTED OUTPUT
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.*
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.250m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.721.500m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.*
/var/www/import/2014047-0216/YukonGold.A2014047.1620.250m.jpg
/var/www/import/2014047-0216/YukonGold.A2014047.1620.500m.jpg
You should use it inside a RegexIterator:
// Notice that there is no expansion pattern used here
$path = '/var/www/import/2014047-0216/YukonGold.A2014047.1620.';
$re = '~\Q' . $path . '\E(?:[^.]+\.)?\w+$~';
$regexIterator = new RegexIterator(new GlobIterator("{$path}*"), $re);
foreach ($regexIterator as $filename) {
echo $filename . "\n";
}
So I have got this far on my own but It looks like I have found the limit of my PHP knowledge (which isn't very much at all!). This script is for filtering filenames (game roms/iso's etc). It has other ways of filtering too but I've just highlighted the section I'm trying to add. I want a external .txt file I can put names of files in like so (separated by a single line break):
Pacman 2 (USA)
Space Invaders (USA)
Asteroids (USA)
Something Else (Europe)
And then running the script will search the directory and place any matching filenames in the "removed" folder. It loops fine with all the other filtering techniques it uses. I'm just trying to add my own (unsuccessfully!)
$gameList = trim(shell_exec("ls -1"));
$gameArray = explode("\n", $gameList);
$file = file_get_contents('manualremove.txt');
$manualRemovePattern = '/(' . str_replace(PHP_EOL, "|", $file) . ')/';
shell_exec('mkdir -p Removed');
foreach($gameArray as $thisGame) {
if(!$thisGame) continue;
// Probably already been removed
if(!file_exists($thisGame)) continue;
if(preg_match ($manualRemovePattern , $thisGame)) {
echo "{$thisGame} is on the manual remove list. Moving to Removed folder.\n";
shell_exec("mv \"{$thisGame}\" Removed/");
continue;
So this is working when I put names of games with no spaces or brackets in the .txt file. But spaces or brackets (or both) are breaking it's functionality. Could someone help me out?
Many thanks!
Replace the fourth line in the code you supplied with
$manualRemovePattern = "/(?:" . implode("|", array_map(function($i) {
return preg_quote(trim($i), "/");
}, explode(PHP_EOL, $file))) . ')/';
The main idea is:
Split the file contents you obtained into lines with explode(PHP_EOL, $file)
Then you need to iterate over the array and modify each item in the array (which can be done with array_map)
Modifying the array items involves adding escaping \ before any special regex metacharacter and a regex delimiter chosen by you (in this case, /), and this is done with preg_quote(trim($i), "/")
Note I remove any leading/trailing spaces with trim from the array items - just in case.
To match them as whole words, use word boundaries:
$manualRemovePattern = '/\b(?:' . implode('|', array_map(function($i) {
return preg_quote(trim($i), '/');
}, explode(PHP_EOL, $file))) . ')\b/';
To match them as whole strings, use ^/$ anchors:
$manualRemovePattern = '/^(?:' . implode('|', array_map(function($i) {
return preg_quote(trim($i), '/');
}, explode(PHP_EOL, $file))) . ')$/';
I have a file that will get modify from time to time and I need to track the file name each time there are new changes to the file.
I expect to a sequence of file names eventually, for example: first-filename-1701.txt, 2nd-filename-1701(1).txt, 3rd-filename-1701(2).txt and etc..
From the results of my code below, it is producing the file names as: first-filename-1701.txt, 2nd-filename-1701(1).txt, 3rd-filename-1702(2).txt, 4th-filename-1703(3).txt and so forth. Can someone kindly points out what I am doing wrong? Regexp is not my every day thing. Thanks.
$name = 'new-foo-bar-1701(1).txt';
$re1='.*?'; # Non-greedy match on filler
$re2='\(([\d]+)\)'; # Round Braces 1
// set new filename
$_name = "";
// check if true
if($c=preg_match_all("/".$re1.$re2."/is", $name, $matches))
{
$rbraces = $matches[1][0] + 1;
$_name .= preg_replace("/".$matches[1][0]."/", $rbraces, $name);
}
else
{
$_name .=$name;
}
print $_name; // new-foo-bar-1702(2).txt
You do not need to find matches to replace them later, that leads to over-replacement. You should replace "on the fly" using a preg_replace_callback that will replace exactly what is being matched (or captured).
$name = 'new-foo-bar-1701(1).txt';
$re1='.*'; # Greedy match on filler
$re2='\((\d+)\)'; # Round Braces 1
// set new filename
$_name = "";
$_name .= preg_replace_callback("/(".$re1. ")".$re2."/", function($m){
return $m[1] . "(" . ($m[2] + 1) . ")";
}, $name);
print $_name;
See the IDEONE demo
Note that since you plan to replace the numbers at the end of the string, greedy dot matching "filler is preferred.
I don't think there is much to change in your code except this line to
$_name .= preg_replace("/\(".$matches[1][0]."\)/", "(".$rbraces.")", $name);
Ideone Demo
Explanation
\d+ is matched to 1, but there is 1 already present twice in your string. So it is replaced to 2702(2).
In order to match 1 specifically from (), you need to put that in your regex as denoted above.
I have an S3 bucket full of images whose naming follows a simple pattern. The first 6 digits group images by listing number, the trailing digit(s) are non-sequential, but follow a reliable pattern (0 thru 99) I'm capturing the six digits that start the filename in a variable $ln.
/*
https://s3.amazonaws.com/stroupenwmls2/602665_10.jpg
https://s3.amazonaws.com/stroupenwmls2/602665_12.jpg
https://s3.amazonaws.com/stroupenwmls2/602665_13.jpg
https://s3.amazonaws.com/stroupenwmls2/602665_15.jpg
*/
What I want to do is populate a 'listing' img src attribute with the url to an image, if one exists for that listing (if not, I provide a no-image.jpg). And I'm looping thru many different listings to create my web page.
I'm struggling with the logic to grab the first image that matches the $listing variable. Here is what I've tried, with no luck (just produces a 0):
$bucket = 'https://s3.amazonaws.com/stroupenwmls2/';
$ln = '602665';
$string = $bucket . $ln . '_';
// match the pattern '_xx.jpg', with 1 or 2 numbers
$image = preg_match('/^_[0-9]{1,2}\.(jpg|jpeg|png|gif)/i', $string);
Then in my web app:
<img src="<?php echo $image ?>">
I'm an idiot when it comes to using preg_match, what I really need is some sort of wildcard parameter. I'm sure I'm making this way too complicated.
The problem is that you're not matching against the image paths, you're matching against what i assume you intend to be part of your regular expression. See below:
$bucket = 'https://s3.amazonaws.com/stroupenwmls2/';
$ln = '602665';
$re = $bucket . $ln . '_' + '[0-9]{1,2}\.(jpg|jpeg|png|gif)';
// let's say you have an array called img_list;
// loop through each path in the list, searching strings
// that match the regular expression constructed in $re.
// if you find a match, return it.
// you'd probably want to define a function to do this for you,
// and call it with the $listing and array as parameters.
foreach (img_list as $img) {
// this returns either 0 or 1 depending on match.
// return the first one, and we're done.
if (preg_match('/^' . $re . '/i', $img)) {
return $img;
}
}
I anyhow got my stuff working with following line, but I really could not understand.
if (preg_match_all('/[^=]*=([^;#]*)/', shell_exec("/home/technoworld/Desktop/test/b '$test'"),$matches))
{
$x = (int) $matches[1][0]; //optionally cast to int
$y = (int) $matches[1][1];
$pcount= round((100*$x)/($x+$y),2);
$ncount= round((100*$y)/($x+$y),2);
}
b is executable file, which gives result something like x=10 and y=20
Can some one explain me whatever inside if()
This: /[^=]*=([^;#]*)/ collects all ...=... things to the $matches array.
[^=] means any character except =
[^;#] means any character except ; and #
() means collect it into $matches explicitly
The $pcount/$ncount makes percent from the values showing theirs ratio.
Pattern details:
[^=]* # is a negated character class that means "all characters except ="
# * is quantifier that means zero or more times
# note that it seems more logical to replace it with +
# that means 1 or more times
= # literal =
( # open the capturing group 1
[^;#]* # all characters except ";" and "#", zero or more times
# (same notice)
) # close the capturing group 1