Quite a while ago I decided to change the way filenames are formatted when users upload a file to my website(which was a great idea!) to include the UNIX_Timestamp in the filename, this proved very useful after unfortunately the timestamps associated with files in my database was wiped, the filename structure has changed considerably and I am currently trying to recover the valid timestamp from the filename, however so far I have only been able to recover half.
Beforehand, I structured the filename to be like this:
dcd1322318879.png - Letters prepended by the unix timestamp.
Then, I allowed people to start logging in and made the filename much more Human Friendly, they now read as follows;
username-09092012-183422.jpeg where username is the logged in users name. The problem I am having now is the fact that firstly, I am awful with regex, for the previous filenames(without the user data and human friendly date) my code was:
$newDate = preg_replace("/[^0-9]/","", $data['name']);
However obviously that will not work now as usernames can contain numbers, and therefore that number will also be included in the final number for the date.
I am currently wondering if there is anyway I can resolve this issue, I guess the fact I added hyphens(-) will be useful as I can use it as a separator, however I have no idea where to start. I need to just get the last two parts of the filename, which contain the date & time so I can then convert them into unix timestamps.
Any help is greatly appreciated
There you go, yet another way, including translation to unix timestamp:
preg_match_all('/[0-9]+/', $string, $matches);
$d = DateTime::createFromFormat('dmY His', $matches[0][0].' '.$matches[0][1]);
$timestamp = $d->getTimestamp();
Try this:
preg_match_all("/(\d{8})-(\d+)/", $str, $matches);
the most easiest way is using
$array = explode ("-", $filename);
print_r ($array);
unless you really want to go with regex, but I dont think its needed since the system is the one doing all the creating. Meaning there will be no user inputs... it can also depends on how you have your script setup.
From your question, I assume that the hyphens can be used as the structure for the regex. That is, usernames and dates won't contain them.
So then, this pretty simple pattern would work:
/(.*?)-(.*?)-(.*)/
Group 1 will contain the username, group 2 contains the date, and group 3 contains the filename (note that the filename (everything after the third hyphen) can be anything at all, including more hyphens).
(the .*? is the dot, quantified at 'zero or more times' by the *, and the ? makes the quantifier lazy, so that the . doesn't just greedily race to the end of the string)
To parse all three components from your file name, try this:
<?php
preg_match(
"/^([\w]+)-(\d{8})-(\d{6})/",
"username-09092012-183422.jpeg",
$matches);
echo "user=[{$matches[1]}]<br/>date=[{$matches[2]}]<br/>time=[{$matches[3]}]<br/>";
?>
Which produces:
user=[username]
date=[09092012]
time=[183422]
You might also consider incorporating the date in your file names as YYYYMMDD. For example:
'09092012' => '20120909'
This will make it easier to sort your data by date should you ever wish to do so.
Related
I'm trying to match files of the following structure in PHP.
Input:
filename.ext1
filename.ext1.ext2
filename.ext3.ext2.ext1
filename.ext4.ext2.ext1.ext4
file name with spaces and no way of knowing how long.ext1
file name with spaces and no way of knowing how long.ext1.ext2
file name with spaces and no way of knowing how long.ext2.ext1.ext3
file name with spaces and no way of knowing how long.ext3.ext1.ext4.ext3
Output:
filename
filename
filename
filename
file name with spaces and no way of knowing how long
file name with spaces and no way of knowing how long
file name with spaces and no way of knowing how long
file name with spaces and no way of knowing how long
What I've already attempted (doesn't work of course and I already understand why):
^(?P<basename>.*)(\.ext4)|(\.ext3)|(\.ext2)|(\.ext1).*$
I'd like to extract the base name of the file and basically strip all extensions, because there's no way of knowing in which order they may appear. I've tried several solutions presented here but they did not work for me. The extensions could be anything alphanumeric of any length.
I'm fairly new to regular expressions and am confused that apparently you cannot simply search forward to the first dot and remove it including everything that comes after.
To learn, I'd also love to see how to do the reverse and just match all the extensions including the first dot.
Update:
I didn't think about file names that contain dots. So obviously my thinking regarding "searching forward" is flawed. Does anyone have a solution for the case
file name with spaces and no. way of knowing how long.ext3.ext1.ext4.ext3
or even
file name with spaces and no way of knowing.how.long.ext3.ext1.ext4.ext3
The latter one would quite possibly only work when certain extensions are given. So please assume ext1-4 are given but are in an unpredictable sequence.
Quick and dirty:
preg_replace("/\.(ext1|ext2|ext3|ext4)/i", "", $filename)
There's no need to use regular expressions for this; PHP has the buildin function basename() for that
Does something simple like this works for you....
^[^.]*
Basically it just matches string before first dot.
This regex should work for you:
^.+?(?=\.[^.]*$)
Online Demo: http://regex101.com/r/uT2oK5
This will find file names before very last dot only. See all the examples included in the link.
am confused that apparently you cannot simply search forward to the first dot and remove it including everything that comes after.
Since regexes are read from left to right, looking for a single dot will lead you straight to the first dot. That said, you would thus be able to use:
preg_replace("/\..*/", "", $filename);
.* matches any characters except newlines.
If the filename has dots, this obviously won't work, since part of the filename will then be removed.
As per update, if you have the specific extensions, you can use something like this:
preg_replace("/(?:\.ext[1-4])+$/m", "", $filename);
regex101 demo
In a broader perspective, you could use something like this if you have an array of extensions at your disposition:
$exts = array(".ext1", ".ext2", ".ext3", ".ext4");
$result = preg_replace("/(?:". preg_quote(join("|",$exts)) .")+$/m", "", $filename);
.*(?=\.)
Try this? Will match all before the last dot even if theres a dot in the file name
This is easy with just plain old php functions. No need for fancy regex.
$name = substr($filename, 0, strpos($filename, '.'));
This won't work for filenames which have a . like your updated example, however in order to achieve this you would likely need to know in advance the extensions which you are likely to encounter.
Something I have noticed on the StackOverflow website:
If you visit the URL of a question on StackOverflow.com:
"https://stackoverflow.com/questions/10721603"
The website adds the name of the question to the end of the URL, so it turns into:
"https://stackoverflow.com/questions/10721603/grid-background-image-using-imagebrush"
This is great, I understand that this makes the URL more meaningful and is probably good as a technique for SEO.
What I wanted to Achieve after seeing this Implementation on StackOverflow
I wish to implement the same thing with my website. I am happy using a header() 301 redirect in order to achieve this, but I am attempting to come up with a tight script that will do the trick.
My Code so Far
Please see it working by clicking here
// Set the title of the page article (This could be from the database). Trimming any spaces either side
$original_name = trim(' How to get file creation & modification date/times in Python with-dash?');
// Replace any characters that are not A-Za-z0-9 or a dash with a space
$replace_strange_characters = preg_replace('/[^\da-z-]/i', " ", $original_name);
// Replace any spaces (or multiple spaces) with a single dash to make it URL friendly
$replace_spaces = preg_replace("/([ ]{1,})/", "-", $replace_strange_characters);
// Remove any trailing slashes
$removed_dashes = preg_replace("/^([\-]{0,})|([\-]{2,})|([\-]{0,})$/", "", $replace_spaces);
// Show the finished name on the screen
print_r($removed_dashes);
The Problem
I have created this code and it works fine by the looks of things, it makes the string URL friendly and readable to the human eye. However, it I would like to see if it is possible to simplify or "tightened it up" a bit... as I feel my code is probably over complicated.
It is not so much that I want it put onto one line, because I could do that by nesting the functions into one another, but I feel that there might be an overall simpler way of achieving it - I am looking for ideas.
In summary, the code achieves the following:
Removes any "strange" characters and replaces them with a space
Replaces any spaces with a dash to make it URL friendly
Returns a string without any spaces, with words separated with dashes and has no trailing spaces or dashes
String is readable (Doesn't contain percentage signs and + symbols like simply using urlencode()
Thanks for your help!
Potential Solutions
I found out whilst writing this that article, that I am looking for what is known as a URL 'slug' and they are indeed useful for SEO.
I found this library on Google code which appears to work well in the first instance.
There is also a notable question on this on SO which can be found here, which has other examples.
I tried to play with preg like you did. However it gets more and more complicated when you start looking at foreign languages.
What I ended up doing was simply trimming the title, and using urlencode
$url_slug = urlencode($title);
Also I had to add those:
$title = str_replace('/','',$title); //Apache doesn't like this character even encoded
$title = str_replace('\\','',$title); //Apache doesn't like this character even encoded
There are also 3rd party libraries such as: http://cubiq.org/the-perfect-php-clean-url-generator
Indeed, you can do that:
$original_name = ' How to get file creation & modification date/times in Python with-dash?';
$result = preg_replace('~[^a-z0-9]++~i', '-', $original_name);
$result = trim($result, '-');
To deal with other alphabets you can use this pattern instead:
~\P{Xan}++~u
or
~[^\pL\pN]++~u
I am looking to strip away a part of the following url yet have no experience with regex or if that's even what I would use.
I have this url:
/var/www/wordpress/wp-content/themes/Aisis-Framework/CoreTheme/AdminPanel/Template/Form/Update.php
I would like to strip away everything to form:
CoreTheme/AdminPanel/Template/Form/Update.php
Is there an easy way to do this, and one that is done such that the amount of content before "CoreTheme" could be x characters long, where x is any number.
It should also not match on the word CoreTheme as it might be any name, it should also not match on Aisis-Framework as that could also be any name...
how ever it is safe to assume that anything after CoreTheme is static. The above string will be turned into, using string replace:
CoreTheme_AdminPanel_Template_Form_Update.php
As I have done in this piece of code:
$class_name = str_replace('/', '_', $path . $name);
where path is, in my solution, CoreTheme/AdminPanel/Template/Form/Update.php and $name is Update
If "/var/www/wordpress/wp-content/themes/Aisis-Framework/" is constant I would just do:
str_replace("/var/www/wordpress/wp-content/themes/Aisis-Framework/","",$path);
Otherwise you would need something constant to get a pattern of, like the number of directories deep or a specific pattern to match.
i'm trying to work out the best way to remove a timestamp from a filename using php's string functions. The timestamp is split from the rest of the filename by an underscore on the left, and the dot to start the file extension on the right (e.g myfile_12343434.jpg) - I only ever want the text prior to the underscore although the length of this can vary. What's the best way to deal with this? Thanks!
edit to leave the extension intact (including e.g. .gd2 and .JPEG) do this:
$new = preg_replace("/_\\d+(\\.[a-z0-9]+)\$/i","\\1",$orig);
this effectively removes only the "_123" part, in a not-so-pretty way. For the purists among us, a version with a lookahead assertion, which only removes the timestamp:
$new = preg_replace("/_\\d+(?=\\.[0-9a-z]+\$)/i","",$orig);
You could use this:
$filename = explode("_", $orig_filename)[0];
The best way is to use preg_replace() to specify an exact match. A good start is something like the following (which will also preserve the extension):
$new = preg_replace("/_\d+/","",$orig);
But since this is a unix timestamp, we can do better by specifying the length of the numeric portion that it will match on:
$new = preg_replace("/_\d{1,11}/","",$orig);
I have an input for users where they are supposed to enter their phone number. The problem is that some people write their phone number with hyphens and spaces in them. I want to put the input trough a filter to remove such things and store only digits in my database.
I figured that I could do some str_replace() for the whitespaces and special chars.
However I think that a better approach would be to pick out just the digits instead of removing everything else. I think that I have heard the term "whitelisting" about this.
Could you please point me in the direction of solving this in PHP?
Example: I want the input "0333 452-123-4" to result in "03334521234"
Thanks!
This is a non-trivial problem because there are lots of colloquialisms and regional differences. Please refer to What is the best way for converting phone numbers into international format (E.164) using Java? It's Java but the same rules apply.
I would say that unless you need something more fully-featured, keep it simple. Create a list of valid regular expressions and check the input against each until you find a match.
If you want it really simple, simply remove non-digits:
$phone = preg_replace('![^\d]+!', '', $phone);
By the way, just picking out the digits is, by definition, the same as removing everything else. If you mean something different you may want to rephrase that.
$number = filter_var(str_replace(array("+","-"), '', $number), FILTER_SANITIZE_NUMBER_INT);
Filter_Var removes everything but pluses and minuses, and str_replace gets rid of those.
or you could use preg_replace
$number = preg_replace('/[^0-9]/', '', $number);
You could do it two ways. Iterate through each index in the string, and run is_numeric() on it, or you could use a regular expression on the string.
On the client side I do recommand using some formating that you design when creating a form. This is good for zip or telephone fields. Take a look at this jquery plugin for a reference. It will much easy later on the server side.