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.
Related
I've recently run into a bug in PHP 7.1 which seems to have come back after being fixed in PHP 5.4.7
The problem is simply that if you pass a url to parse_url() and the url doesn't have a scheme it will return the whole url as if it's just a path. For example:
var_dump(parse_url('google.co.uk/test'))
Result:
array(1) { ["path"]=> string(12) "google.co.uk/test" }
While in reality here it should split into its domain and path.
I run parse_url a few ten million times a day as part of url decryption / encryption functionality. I'm looking for a fast way to fix this edgecase bug or have a reliable alternative to parse_url.
Edit:
Thanks for the helpful responses, here's the solution I used in the end, I hope it helps someone. I won't submit it as an answer because I already marked someone else as correct (which they are) which allowed me to write this.
$parsedUrl = parse_url($uri);
// if the uri has no scheme, it won't think there's a host and will give bad results
if ($parsedUrl !== false && !isset($parsedUrl['host'])) {
// double slash prepended will parse $uri as if it has a schema and no schema will be in the result
$parsedUrl = parse_url('//' . $uri);
}
if ($parsedUrl === false) {
throw new MalformedUrlException('Malformed URL: ' . $uri);
}
// use parsed url as needed
parse_url needs to have information if the given string is the beginning of a url.
this is why parse_url('//domain/path') works -> it will just not output any schema.
now to describe the problem you want to be solved: php would need to know every domain there is and to then be able to decide if this is what the user wanted (basically impossible)
Take for example the following url: 'http://whois.domaintools.com/test.at' -> if I only pass the path it will write 'test.at' -> is this now a path or domain?
I learned how to parse an URL and return me a specific part of it.
For now, I'm currently working in a localhost server, which contains a long basename:
localhost/mydocs/project/wordpress/mexico/cancun
If I want to get the word mexico I would have to count 4 until there.
$url = localhost/mydocs/project/wordpress/mexico/cancun
$parse = parse_url($url);
$path = explode('/', $parse[path]);
echo = $path[4]
Even though it works fine for localhost, when uploading in the server, the basename get shorter and the number 4 can not reach mexico, because the URL becomes:
example.com/mexico/cancun
I'd like to know if there is a global solution for it. I thought about counting backwards, like using -2, so it would start counting from the word "cancun", but I don't know whether is possible or not!
Thank you!
use $path[count($path)-2] -2 being the configurable part.
Note this will only work for numeric indices, like for your case.
This question already has answers here:
Get domain name (not subdomain) in php
(18 answers)
Closed 10 years ago.
I've already seen a bunch of questions on this exact subject, but none seem to solve my problem. I want to create a function that will remove everything from a website address, except for the domain name.
For example if the user inputs: http://www.stackoverflow.com/blahblahblah I want to get stackoverflow, and the same way if the user inputs facebook.com/user/bacon I want to get facebook.
Do anyone know of a function or a way where I can remove certain parts of strings? Maybe it'll search for http, and when found it'll remove everything until after the // Then it'll search for www, if found it'll remove everything until the . Then it keeps everything until the next dot, where it removes everything behind it? Looking at it now, this might cause problems with sites as http://www.en.wikipedia.org because I'll be left with only en.
Any ideas (preferably in PHP, but JavaScript is also welcome)?
EDIT 1:
Thanks to great feedback I think I've been able to work out a function that does what I want:
function getdomain($url) {
$parts = parse_url($url);
if($parts['scheme'] != 'http') {
$url = 'http://'.$url;
}
$parts2 = parse_url($url);
$host = $parts2['host'];
$remove = explode('.', $host);
$result = $remove[0];
if($result == 'www') {
$result = $remove[1];
}
return $result;
}
It's not perfect, at least considering subdomains, but I think it's possible to do something about it. Maybe add a second if statement at the end to check the length of the array. If it's bigger than two, then choose item nr1 instead of item nr0. This obviously gives me trouble related to any domain using .co.uk (because that'll be tree items long, but I don't want to return co). I'll try to work around on it a little bit, and see what I come up with. I'd be glad if some of you PHP gurus out there could take a look as well. I'm not as skilled or as experienced as any of you... :P
Use parse_url to split the URL into the different parts. What you need is the hostname. Then you will want to split it by the dot and get the first part:
$url = 'http://facebook.com/blahblah';
$parts = parse_url($url);
$host = $parts['host']; // facebook.com
$foo = explode('.', $host);
$result = $foo[0]; // facebook
You can use the parse_url function from PHP which returns exactly what you want - see
Use the parse_url method in php to get domain.com and then use replace .com with empty string.
I am a little rusty on my regular expressions but this should work.
$url='http://www.en.wikipedia.org';
$domain = parse_url($url, PHP_URL_HOST); //Will return en.wikipedia.org
$domain = preg_replace('\.com|\.org', '', $domain);
http://php.net/manual/en/function.parse-url.php
PHP REGEX: Get domain from URL
http://rubular.com/r/MvyPO9ijnQ //Check regular expressions
You're looking for info on Regular Expression. It's a bit complicated, so be prepared to read up. In your case, you'll best utilize preg_match and preg_replace. It searches for a match based on your pattern and replaces the matches with your replacement.
preg_match
preg_replace
I'd start with a pattern like this: find .com, .net or .org and delete it and everything after it. Then find the last . and delete it and everything in front of it. Finally, if // exists, delete it and everything in front of it.
if (preg_match("/^http:\/\//i",$url))
preg_replace("/^http:\/\//i","",$url);
if (preg_match("/www./i",$url))
preg_replace("/www./i","",$url);
if (preg_match("/.com/i",$url))
preg_replace("/.com/i","",$url);
if (preg_match("/\/*$/",$url))
preg_replace("/\/*$/","",$url);
^ = at the start of the string
i = case insensitive
\ = escape char
$ = the end of the string
This will have to be played around with and tweaked, but it should get your pointed in the right direction.
Javascript:
document.domain.replace(".com","")
PHP:
$url = 'http://google.com/something/something';
$parse = parse_url($url);
echo str_replace(".com","", $parse['host']); //returns google
This is quite a quick method but should do what you want in PHP:
function getDomain( $URL ) {
return explode('.',$URL)[1];
}
I will update it when I get chance but basically it splits the URL into pieces by the full stop and then returns the second item which should be the domain. A bit more logic would be required for longer domains such as www.abc.xyz.com but for normal urls it would suffice.
How can I check the URL path for certain folders? I ask so that if we're in a certain folder, we can make a tab selected in the nav bar (just apply a style to that specific li).
So far I know
$pagePath = $_SERVER['REQUEST_URI'];
So I can get a return that says something like /music/song/120/ (or whatever it is). What kind of php function can I use that says
if $pagePath has "music", then do this. Meaning, if the path is /music/ or /music/song, I should be able to
I plan on using this multiple times,
if $pagePath has downloads do this
if $pathPath has band do this
and so on.
Any suggestions?
You could explode() the path on / and then use in_array() to check for existence.
However, this could yield problems with paths like /bands/something/music where the state would depend on whether you check for bands before music or vice versa. In that case you could explode() with $limit = 2 (to get only two parts, i.e., split on first / only) and compare your predefined path segments to the first part of the exploded path.
E.g.
$path = trim('/bands/something/music', '/');
$parts = explode('/', $path, 2); // ['bands', 'something/music']
switch ($parts[0]) {
case 'music':
// ...
case 'bands':
// ...
}
Try strpos()
e.g.
if(strpos($_SERVER['REQUEST_URI'],'music')>0)
{
# URL contains music
}
A quick way: you could use strpos: http://www.php.net/manual/en/function.strpos.php
PHP beginner's question.
I need to keep image paths as following in the database for the admin backend.
../../../../assets/images/subfolder/myimage.jpg
However I need image paths as follows for the front-end.
assets/images/subfolder/myimage.jpg
What is the best way to change this by PHP?
I thought about substr(), but I am wondering if there is better ways.
Thanks in advance.
you should save your image path in an application variable and can access from both admin and frontend
If ../../../../ is fixed, then substr will work. If not, try something like this:
newpath=substr(strpos(path, "assets"));
It might seem like an odd choice at first but you could use ltrim. In the following example, all ../'s will be removed from the beginning of $path.
The dots in the second argument have to be escaped because PHP would treat them as a range otherwise.
$path = ltrim('../../../../assets/images/subfolder/myimage.jpg', '\\.\\./');
$path will then be:
assets/images/subfolder/myimage.jpg
I suggest this
$path = "../../../../assets/images/subfolder/myimage.jpg";
$root = "../../../../";
$root_len = strlen($root);
if(substr($path, 0, $root_len) == $root){
echo substr($path, $root_len);
} else {
//not comparable
}
In this way you have a sort of control on which directory to consider as root for your images