Where does the glob() function start searching for file - php

What is the php's glob function starting point for pattern searching when given arguments like below.
$dirs = glob('*');
Does it resolve its path like many file handling functions.

The manual http://php.net/manual/en/function.glob.php states:
The glob() function searches for all the pathnames matching pattern according to the rules used by the libc glob() function, which is similar to the rules used by common shells.
and pulled from https://www.gnu.org/software/libc/manual/html_node/Calling-Glob.html and using "libc glob() function" as a starting reference, states:
The function glob does globbing using the pattern pattern in the current directory. It puts the result in a newly allocated vector, and stores the size and address of this vector into *vector-ptr. The argument flags is a combination of bit flags; see Flags for Globbing, for details of the flags.
Side note: The folks at PHP.net may have felt they didn't see the need to repeat those rules. Why? I don't know that and would be out of the scope of the question. It would however, have been nice for them to include a hyperlink as a reference (starting) point.

That will be the folder where your script is located.
The function glob does globbing using the requested pattern in the current directory.

Related

Can you accurately process a directory structure by URI alone?

Take the following complex URI (or path, what have you).
/directory/subdirectory/flashy-seo-directory/?query=123&complexvar=abc/123etc
Take this simpler one.
/directory/?query=123
What methodology would you use to accurate process the URI to seperate the directory from the filename/query/etc?
I know how to do this in simple, expected, and typical case scenarios where everything is formatted "normally" or "favorably" but what I'd like to know is if the following example will accurately cover all possible valid directory names/structures/queries/etc. For example I once seen a URI like this that I don't quite understand: /directory/index.php/something/?query=123. Not even sure what's going on there.
Methodology (not dependent on any specific programming language, though I am using PHP for this)
explode entire URI by / placing each bit in a neat array
$bits = explode( '/', $uri );
Loop through each array item and determine(?) at what point we've "reached" the portion of the URI that is no longer directory structure
Note which array key is no longer directory structure and implode the prior keys to assemble the directory
--
My ideas for Step 2. was going to be basically check to make sure there are no query specific characters (?, &, =). I haven't seen any directories with .s in them, but as you can see you can have a query variable such as ?q=abc/123 so simply checking for / wouldn't work. I've seen directories with the ~ symbol so it so a simple [A-Za-z0-9-] regex might not work in every scenario. Wondering how Step 2. can be done accurately.
This is needed seeing as the URI can capture a "virtual directory" the script may be running under that doesn't actually exist anywhere, perhaps via .htaccess for SEO or what have you. And so needs to be properly and accurately "accounted for" in order to have robust and flexible functionality throughout.
If you are only interested in the path part, and there is no host involved, then you only need to split (explode) the string at the first valid URI path delimiter.
Valid delimiters: ; # ?
$uri = "/directory/flashy-seo-directory/?query=123&complexvar=abc/123etc";
foreach (str_split("#;?") as $dlm) {
$uri = str_contains($uri, $dlm) ? explode($dlm, $uri, 2)[0] : $uri;
}
echo($uri);
Result:
/directory/flashy-seo-directory/
I suppose you're looking for parse_url()
https://www.php.net/manual/en/function.parse-url

How to separate filename from path? basename() versus preg_split() with array_pop()

Why use basename() in PHP scripts if what this function is actually doing may be written in 2 lines:
$subFolders = preg_split("!\\\|\\/!ui", $path); // explode on `\` or `/`
$name = array_pop($subFolder); // extract last element's value (filename)
Am I missing something?
However I guess this code above may not work correctly if file name has some \ or / in it. But that's not possible, right?
PHP may run on many different systems with many different filesystems and naming conventions. Using a function like basename() guarantees (or at least, is supposed to guarantee) a correct result regardless of the platform. This increases the code's portability.
Also, compare a simple basename() call to your code - which is more readable, and more obvious to other programmers in regards to what it is supposed to do?

Clean directory pathname php

basically what i want to do is:
include($_SERVER['REQUEST_URI']);
Problem is, that this is not safe.
It would be safe, if it would point to "/allowed/directory/" or it's subdirectories.
So i test for that with startsWith("/allowed/directory/").
However I'm still afraid of something like:
"allowed/directory/../../bad/directory"
Is there a way to check whether a string points to a specific directory or one of it's subdirectories in php?
(Basically apply all the /../ - or am i missing another security flaw?)
PHP function realpath() should remove the ../ /// from the path.
Though you are right, this can be a fairly dangerous operation. IMO the paths should be restricted to a known set of characters (like "a-zA-Z_" and / ). Also, path strings should be limited to a known size (like 256 chars).
Once you've determined the prefix is correct, you can use preg_match like this:
if(preg_match("#^[A-Za-z0-9/]+#", $string) {
// correct
}
else {
// incorrect
}
The variable part you're checking (non-static part) you typically want to be just alpha numeric.
As long as you're using include to include local PHP fils and properly validate your input (keeping that input simple) you should be fine. Just be extremely careful and test things throughly. You typically want to avoid passing user input into sensitive functions such as include. But with a framework, it's sometimes difficult to avoid that.
Another thing you could do is have a list of valid inputs to do an exact comparison. You could have this in an ini file and load it with parse_ini_file. This is usually the safest thing to do, just a little more work. You can also use a PHP file with an array, which works better with APC.

PHP Regex specify multiple paths using glob()

glob("aaafolder/*php")
glob("bbbfolder/*php")
glob("cccfolder/*php")
Is it possible to simplify this?
glob("(?=aaafolder/*php)(?=bbbfolder/*php)(?=cccfolder/*php)")
The above returns nothing.
This note on the manual page of glob() seems to answer your question, saying that glob is not limited to a single directory : using GLOB_BRACE, you can specify several directories.
I'm quoting the example that #Ultimater gives there :
$results=glob("{includes/*.php,core/*.php}",GLOB_BRACE);
User-notes on the manual pages often contain useful informations and examples ;-)
As the PHP manual said, its the GLOB_BRACE flag.
glob("{aaafolder/*php,bbbfolder/*php,cccfolder/*php}", GLOB_BRACE)

What kind of special characters can glob pattern handle?

So far I have only worked with *, but, are there something like lookaheads, groups?
I would like to get all *.php except controller.php.
What I have to alter in this glob(dirname(__FILE__) . DIRECTORY_SEPARATOR . '*.php') call, to exclude controller.php?
Or should I avoid glob and work with something else instead?
php glob() uses the rules used by the libc glob() function, which is similar to the rules used by common shells. So the patterns that you are allowed to use are rather limited.
glob() returns an array of all the paths that match the given pattern. Filtering controller.php out the result array is one solution.
As per http://www.manpagez.com/man/3/glob/: (the backend behind php's glob()) The glob() function is a pathname generator that implements the rules for file name pattern matching used by the shell.
It is a single filter, no exceptions. If you want *.php, you'll get *.php.
Try this,
<?php
$availableFiles = glob("*.txt");
foreach ($availableFiles as $key => $filename) {
if($filename == "controller.php"){
unset($availableFiles[$key]);
}
}
echo "<pre>"; print_r($availableFiles);
?>

Categories