PHP stream context -> how to use in this scenario? - php

I have a system that stores user comments in its own individual json file. I use scandir(); on the directory which gets all files and folders, but how do I limit it to json files, I don't want other files such as "." and ".." in the array because I need an accurate count.
I checked out the info on php.net but couldn't figure it out, perhaps you know of a resource you can point me toward, or which function to use.

This is a lovely example where the PHP library comes to the rescue. FilterIterator is a class that you extend and override its accept method to use only the files you want. In this case we use a standard FilesystemIterator to iterate over a directory. You could also use a RecursiveDirectoryIterator if you want to search for json files in sub-directories. This example iterates over json files in the current directory:
class StorageFilterIterator extends FilterIterator {
function accept() {
$item = $this->getInnerIterator()->current();
return $item->isFile() && $item->getExtension() === 'json';
}
}
$storageFiles = new StorageFilterIterator(new FilesystemIterator(__DIR__));
foreach ($storageFiles as $item) {
echo $item;
}
getExtension exists in PHP >= 5.3.6
Another lesser-known part of the Standard PHP Library (SPL) is iterator_to_array. So if you want all of the items in an array instead of just iterating over them, you can do the following:
$storageFiles = iterator_to_array(
new StorageFilterIterator(new FilesystemIterator(__DIR__))
);

There are no stream context parameters that will help you filter out the types of files.
Assuming that your JSON files are saved with the .json extension, you just have to filter out the array based on the file extensions.
You can use readdir() to build a list of files, or simply loop over the results you get from scandir and create a new array from that.
Here is an example using readdir:
$files = array();
$dh = opendir($path);
while (($file = readdir($dh) !== false) {
if (pathinfo($path . '/' . $file, PATHINFO_EXTENSION) !== 'json') continue;
$files[] = $path . '/' . $file;
}
closedir($dh);
// $files now has an array of json files

Related

PHP file include script not fully working on LINUX machines

I have a lot of functions and classes that I have included in my website.
With the help of stackoverflow I recieved a script that automaticly includes all files in a folder and its subfolders: PHP: Automatic Include
When testing the script it always worked and I never had any problems with it.
But recently when switching from a windows server to a linux server it gives problems with extension of classes.
PHP Fatal error: Class 'AcumulusExportBase' not found in path/functions/classes/Acumulus/AcumulusExportWorkshop.php on line 3, referer: pagesite/?page_id=346
AcumulusExportWorkshop extends from AcumulusExportBase.
This all fully works on windows but refuses to work on linux.
I can fix this creating a include_once 'AcumulusExportBase.php'; but if there is a better solution it all seems unnecessary and annyoing work.
The code I use is the following:
load_folder(dirname(__FILE__));
function load_folder($dir, $ext = '.php') {
if (substr($dir, -1) != '/') { $dir = "$dir/"; }
if($dh = opendir($dir)) {
$files = array();
$inner_files = array();
while($file = readdir($dh)) {
if($file != "." and $file != ".." and $file[0] != '.') {
if(is_dir($dir . $file)) {
$inner_files = load_folder($dir . $file);
if(is_array($inner_files)) $files = array_merge($files, $inner_files);
} else {
array_push($files, $dir . $file);
}
}
}
closedir($dh);
foreach ($files as $file) {
if (is_file($file) and file_exists($file)) {
$lenght = strlen($ext);
if (substr($file, -$lenght) == $ext && $file != 'loader.php') { require_once($file); }
}
}
}
}
Can anyone tell me how it is that windows has no problems with extension classes and linux does? Also is there a fix for the problem without having to manual include the base classes?
Have you verified that AcumulusExportBase is included before AcumulusExportWorkshop under Linux? PHP is sensitive to the order of imports.
Both other answers are correct (and I've upvoted them both). Your problem will be the order the files are loaded (see Mark's response) and the recursion is also wrong (see KIKO).
However there is a better way of doing what you want: use an autoloader. http://php.net/manual/en/language.oop5.autoload.php
First time is confusing, but once you've grasped it, it's a lovely way of loading files.
Basically you say "If I need class X and it's not loaded, then load file Y.php".
If you're being super-lazy and don't want to specify each class then you can say "If I need class X and it's not loaded, run through the directory structure looking for a file called X.php and load that, my class will be in there." You can mix in what you have above to do this.
This way, you can load AcumulusExportWorkshop first, and then it looks for AcumulusExportBase afterwards and runs happily.
And, more beneficially, you only load what you need. If you never need the class, it never gets loaded.
I would like to answer your question, but regretably I do not have a Windows PHP server installed. I can however look at, and test, your code. The first thing I notice is the malformed recursion. To get the 'inner_files', recursion is used, which is fine, but this requires your function to return a value, namely the array of files. It does not. Furthermore, although you're using 'require_once', this is called on each recursion, meaning you try to include 'deep' files many times. In short: It's time to somewhat simplify your code.
load_folder(dirname(__FILE__));
function load_folder($dir,$ext = '.php')
{
if (substr($dir,-1) != '/') $dir = $dir.'/';
if ($handle = opendir($dir))
{
while($file = readdir($handle))
{
if (($file != '.') && ($file != '..') && ($file[0] != '.'))
{
if (is_dir($dir.$file)) load_folder($dir.$file,$ext);
else
{
if ((substr($file,-strlen($ext)) == $ext) &&
($file != 'loader.php') &&
file_exists($dir.$file)) require_once($dir.$file);
}
}
}
closedir($handle);
}
}
This works under linux, and performs the same task. I corrected the fact that $ext was missing from internal load_folder().
My advise is to never blindly copy code you find on the internet. Always check it, and then check again. Make sure you understand how it work. If you do not your projects will be littered with bug and impossible for anyone to maintain.
As Robbie stated, both of the other answers are correct, and an autoloader is the ideal solution.
An autoloader may seem (at first) to be slightly more complicated, but it presents benefits that are genuinely significant and make it well worth using.
Here are a few of them:
You do not need to manually include or require files.
You do not need to worry about files being loaded in the correct sequence - the interpreter will load any dependencies automatically. (In your case, the differences in the Windows and Linux operating system exposed this weakness in the existing code)
You can avoid loading files that are not needed.
The interpreter does not need to parse unnecessary classes and code.
Here are some things you should know about autoloaders:
You can have as many autoloaders as you need and want - they are stored in a stack and executed in sequence. If the first one does not load the class, the next one is used, and so on, until the class is loaded or there are no more autoloaders to try.
An autoloader is a callable - either a method of a class, or a function.
Exactly how you implement the autoloader is up to you - so if your project has a specific directory structure that relates to the class type or hierarchy, you can instruct it to look in specific directories, making it more efficient.
Most of us like to keep our classes in separate files. This makes it easier to find the classes we are interested in, and keeps the files smaller, which makes them easier to understand.
PHP does not enforce any kind of naming convention when it comes to the names of the files we use, but most developers prefer to save Classes in files with file names that relate to the class name.
The autoloader feature assumes that there is a way to load the correct file when presented with the file name. So a good practice is to have a simple way of generating the file name from the class name - the simplest is to use the class name as the file name.
Here is my preferred autoloader - which I have adapted from code by Jess Telford that I found online when I was learning PHPUnit - (http://jes.st/2011/phpunit-bootstrap-and-autoloading-classes/)
class ClassDirectoryAutoLoader {
static private $classNamesDirectory = array();
public static function crawlDirectory($directory) {
$dir = new DirectoryIterator($directory);
foreach ($dir as $file) {
self::addClassesAndCrawlDirectories($file);
}
}
private static function addClassesAndCrawlDirectories($file){
if (self::isRealDirectory($file)) {
self::crawlDirectory($file->getPathname());
} elseif (self::isAPhpFile($file)) {
self::saveClassFilename($file);
}
}
private static function isRealDirectory($file){
// ignore links, self and parent
return $file->isDir() && !$file->isLink() && !$file->isDot();
}
private static function isAPhpFile($file){
//ends in .php
return substr($file->getFilename(), -4) === '.php';
}
private static function saveClassFilename($file){
//assumes that the filename is the same as the classname
$className = substr($file->getFilename(), 0, -4);
self::registerClass($className, $file->getPathname());
}
public static function registerClass($className, $fileName) {
self::$classNamesDirectory[$className] = $fileName;
}
public static function loadClass($className) {
if (isset(self::$classNamesDirectory[$className])) {
require_once(self::$classNamesDirectory[$className]);
}
}
}
$classDir = dirname(__FILE__) . '/../classes'; // replace with the root directory for your class files
ClassDirectoryAutoLoader::crawlDirectory($classDir);
spl_autoload_register(array('ClassDirectoryAutoLoader', 'loadClass'));
What this code does is
Recurse through the directories (from the classDir), looking for .php files.
Builds an associative array that maps the classname to the full filename.
Registers an autoloader (the loadClass method).
When the interpreter tries to instantiate a class that is not defined, it will run this autoloader, which will:
Check if the file is stored in the associative array.
Require the file if it is found.
I like this autoloader because:
It's simple.
It's general - you can use it in virtually any project that follows a few simple conventions (see below).
It only crawls the directory tree once, not every time a new class is instantiated.
It only requires the files that are needed.
The loadClass method is super-efficient, simple performing a lookup and a require.
This code makes some assumptions:
All of the classes are stored in a specific directory.
All of the files in that directory contain classes.
The file name exactly matches the class name.
There are no side effects from requiring a file (i.e. the file contains only a class definition, no procedural code).
Breaking these assumptions will break this autoloader.
These are the conventions you need to follow to make use of this autoloader:
Keep all classes under a single directory.
Only class definition files under the class directory.
Make a seperate file for each public class.
Name each file after the class it contains.
No procedural code with side effects in these class definition files.
Well, I am building a System which uses an auto-loader, So here's what I made:
function endswith($string,$tidbit){
// Length of string
$strlen = strlen($string);
// Length of ending
$tidlen = strlen($tidbit);
// If the tidbit is of the right length (less than or equal to the length of the string)
if($tidlen <= $strlen){
// Substring requires a place to start the copying
$tidstart = $strlen - $tidlen;
// Get $tidlen characters off the end of $string
$endofstring = substr($string, $tidstart, $tidlen);
// If the $tidbit matches the end of the string
$ret = ($endofstring == $tidbit);
return $ret;
} else {
// Failure
return -1;
}
}
// Working
function ush_load_path($path) {
if (is_dir($path)) {
if (is_file($path . '/' . (explode('/', $path)[count(explode('/', $path)) - 1]) . '.inc')) {
require_once $path . '/' . (explode('/', $path)[count(explode('/', $path)) - 1]) . '.inc';
}
ush_load_path_recursive($path);
// If it is a file
} else if (is_file($path)) {
require_once $path;
// Failure
} else {
return false;
}
}
function ush_load_path_recursive($path) {
// Directory RESOURCE
$path_dir = opendir($path);
// Go through the entries of the specified directory
while (false != ($entry = readdir($path_dir))) {
if ($entry != '.' && $entry != '..') {
// Create Full Path
$path_ext = $path . '/' . $entry;
// Development
if (is_dir($path_ext)) {
ush_load_path_recursive($path_ext);
} else if (is_file($path_ext)) {
if (ush_is_phplib($path_ext)) {
print $path_ext . '<br />';
require_once $path_ext;
} else {
// Do nothing
}
}
}
}
}
// Working
function ush_is_phplib($path) {
return endswith($path, '.inc');
}
Can you do a print_r($files) after the closedir($dh); and before the foreach so we could see which files are actually being loaded and in which order?
load_folder(dirname(__FILE__));
function load_folder($dir, $ext = '.php') {
if (substr($dir, -1) != '/') { $dir = "$dir/"; }
clearstatcache(); // added to clear path cache
if($dh = opendir($dir)) {
$files = array();
$inner_files = array();
while($file = readdir($dh)) {
if($file != "." and $file != ".." and $file[0] != '.') {
if(is_dir($dir . $file)) {
$inner_files = load_folder($dir . $file);
if(is_array($inner_files)) $files = array_merge($files, $inner_files);
} else {
array_push($files, $dir . $file);
}
}
}
closedir($dh);
clearstatcache($dir); // added to clear path cache
foreach ($files as $file) {
if (is_file($file) and file_exists($file)) {
$lenght = strlen($ext);
if (substr($file, -$lenght) == $ext && $file != 'loader.php') { require_once($file); }
}
}
}
}
It seems that clearstatcache($path) must be called before any file-handling functions on the symlink'd dir. Php isn't caching symlink'd dirs properly.
I might be missing some point here, but it gives me the creeps just seeing that script...I am making the assumption that you call that function with a folder where you keep all your php function files and what not, which are all included, even if only one of those files is needed for the actual script to work.
Am I missing something here, or is this how it is working? If not, I am mislead by the description and function code.
If this is really what you are doing, there are better ways of including the needed files, without all those unnecessary inclusions.
I have a class that handles all my script loading. All I have to do is register the loading function:
spl_autoload_register('Modulehandler::Autoloader');
Then, whenever a new file is required, PHP will use my function to lookup the file.
Here is the function itself:
static function Autoloader($className) {
$files = array($className);
$lowerClass = strtolower($className);
if (strcmp($className, $lowerClass) != 0) $files[] = $lowerClass;
foreach (self::$modules as $moduleName => $module) {
foreach ($files as $className) {
$file = "{$module}/classes/{$className}.php";
if (file_exists($file)) {
require $file;
break;
}
}
}
}
This class has a little more to itself than just the loading, as I also have the ability to add Modules to the loader, so I only search the folders from the included modules, allowing some performance gain over the alternative of searching through all the modules. Besides that, there is the obvious benefit of only including the necessary files.
I hope this fits into what you need, and helps you out.
Have you checked whether that AcumulusExportBase is properly included in AcumulusExportWorkshop ?
And please keep in mind that Linux is very much case sensitive so the file name should in proper case.
LIKE a.JPG can be called a.jpg in windows but in LINUX we need to maintain the proper case.
The primary difference is the type of filesystem. When you use Mac, or Windows they are both not case sensitive, but Linux actually treats the filename "Capitalized.php" as "CAPITALIZED.PHP"
That is why most popular frameworks have lower cased filenames.

How to Delete ALL .txt files From a Directory using PHP

Im trying to Delete ALL Text files from a directory using a php script.
Here is what I have tried.....
<?php array_map('unlink', glob("/paste/*.txt")); ?>
I dont get an Error when I run this, yet It doesnt do the job.
Is there a snippet for this? Im not sure what else to try.
Your Implementation works all you need to do is use Use full PATH
Example
$fullPath = __DIR__ . "/test/" ;
array_map('unlink', glob( "$fullPath*.log"))
I expanded the submitted answers a little bit so that you can flexibly and recursively unlink text files located underneath as it's often the case.
// #param string Target directory
// #param string Target file extension
// #return boolean True on success, False on failure
function unlink_recursive($dir_name, $ext) {
// Exit if there's no such directory
if (!file_exists($dir_name)) {
return false;
}
// Open the target directory
$dir_handle = dir($dir_name);
// Take entries in the directory one at a time
while (false !== ($entry = $dir_handle->read())) {
if ($entry == '.' || $entry == '..') {
continue;
}
$abs_name = "$dir_name/$entry";
if (is_file($abs_name) && preg_match("/^.+\.$ext$/", $entry)) {
if (unlink($abs_name)) {
continue;
}
return false;
}
// Recurse on the children if the current entry happens to be a "directory"
if (is_dir($abs_name) || is_link($abs_name)) {
unlink_recursive($abs_name, $ext);
}
}
$dir_handle->close();
return true;
}
You could modify the method below but be careful. Make sure you have permissions to delete files. If all else fails, send an exec command and let linux do it
static function getFiles($directory) {
$looper = new RecursiveDirectoryIterator($directory);
foreach (new RecursiveIteratorIterator($looper) as $filename => $cur) {
$ext = trim($cur->getExtension());
if($ext=="txt"){
// remove file:
}
}
return $out;
}
i have modified submitted answers and made my own version,
in which i have made function which will iterate recursively in current directory and its all child level directories,
and it will unlink all the files with extension of .txt or whatever .[extension] you want to remove from all the directories, sub-directories and its all child level directories.
i have used :
glob() From the php doc:
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.
i have used GLOB_ONLYDIR flag because it will iterate through only directories, so it will be easier to get only directories and unlink the desired files from that directory.
<?php
//extension of files you want to remove.
$remove_ext = 'txt';
//remove desired extension files in current directory
array_map('unlink', glob("./*.$remove_ext"));
// below function will remove desired extensions files from all the directories recursively.
function removeRecursive($directory, $ext) {
array_map('unlink', glob("$directory/*.$ext"));
foreach (glob("$directory/*",GLOB_ONLYDIR) as $dir) {
removeRecursive($dir, $ext);
}
return true;
}
//traverse through all the directories in current directory
foreach (glob('./*',GLOB_ONLYDIR) as $dir) {
removeRecursive($dir, $remove_ext);
}
?>
For anyone who wonder how to delete (for example: All PDF files under public directory) you can do this:
array_map('unlink', glob( public_path('*.pdf')));

Why does isDot() fail on me? (PHP)

I'm finalizing a code segment that lists the files in a directory. I have no problems listing the files in a directory but for some reason I can get the isDot() method to work to make sure the file isn't a "." or ".." . The following below results in this error:
Fatal error: Call to undefined method SplFileInfo::isDot() in ....
Before I switched over to using the Recursive Iterator I was using the Directory Iterator and it worked fine. Is there anything wrong with the code below? It should work.
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathToFolder));
//if there is a subdirectory it makes sure the proper extension is passed
foreach($files as $name => $file){
if (!$file->isDot()) { //this is where it shuts me down
$realfile = str_replace($pathToFolder, "", $file);
$url = getDownloadLink($folderID, $realfile);
$fileArray[] = $url;
}
}
This is, because DirectoryIterator::current() (the method, that is call within a foreach-loop) returns an object, which is itself of type DirectoryIterator. FileSystemIterator (that RecursiveDirectoryIterator extends) returns an object of SplFileInfo be default. You can influence, what is return, via flags
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$pathToFolder,
FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_SELF));
But in your case, you don't need to test, if an item is a dot-file. Just set FilesystemIterator::SKIP_DOTS and they will not appear at all. Note, that this is also the default behavior.
The other answer is excellent, but for a different approach you can set the
SKIP_DOTS flag:
<?php
$o_dir = new RecursiveDirectoryIterator($pathToFolder);
$o_dir->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$o_iter = new RecursiveIteratorIterator($o_dir);
foreach ($o_iter as $o_info) {
echo $o_info->getPathname(), "\n";
}
https://php.net/filesystemiterator.setflags

PHP scandir causing extra files

Why is it when i use scandir using PHP i get extra values
$portID = $this->id;
$dir = '/home/sites/mydomain.com/public_html/public/images/'.$portID;
$contents = scandir($dir);
Is there something i dont know about the function which produces more values than are actually in the folder?
here's an alternative using opendir
$dir = "/your/path";
if (is_dir($dir)) {
if ($d = opendir($dir)) {
while (($file = readdir($d)) !== false) {
if ( $file != "." && $file != ".." ){
echo "filename: $file \n";
$files[]=$file;
}
}
closedir($d);
}
}
if you insist on using scandir(), then use a loop to go through the array of files returned by scandir(), and then remove those you don't want from the array
I don't have enough rep to comment on just somebody's answer so this will have to be in a separate answer. As of PHP 5.3 there is the FilesystemIterator which extends the DirectoryIterator and skips dot-files by default.
Here is the easiest way to get rid of the dots and unnecessary files or directories.
// remove unnecessary dots etc
$result = array_diff(scandir('/dir/to/scan/'), array('.', '..', '.DS_Store'));
print_r($result);
Hope this is helpful. Thanks!
there's nothing wrong with Pekka's answer; I'll just add a more declarative and mockable realization from SPL:
class DirectoryFilterDots extends RecursiveFilterIterator
{
function __construct($path)
{
parent::__construct(new RecursiveDirectoryIterator($path));
}
function accept()
{
return !$this->getInnerIterator()->isDot();
}
function key()
{
return $this->getInnerIterator()->getPathname();
}
}
While it's hard to tell without the actual output of scandir(), I guess you mean the additional . and .. entries.
They show up in the examples in the manual as well. You will have to filter them out manually.
. refers to the current directory
.. refers to the parent directory.
This tradition comes from the Unix world, where exactly historically, I don't know. I guess it is because it allows you to quickly see the permissions for the current and parent directories on each call of ls.

How to include() all PHP files from a directory?

In PHP can I include a directory of scripts?
i.e. Instead of:
include('classes/Class1.php');
include('classes/Class2.php');
is there something like:
include('classes/*');
Couldn't seem to find a good way of including a collection of about 10 sub-classes for a particular class.
foreach (glob("classes/*.php") as $filename)
{
include $filename;
}
Here is the way I include lots of classes from several folders in PHP 5. This will only work if you have classes though.
/*Directories that contain classes*/
$classesDir = array (
ROOT_DIR.'classes/',
ROOT_DIR.'firephp/',
ROOT_DIR.'includes/'
);
function __autoload($class_name) {
global $classesDir;
foreach ($classesDir as $directory) {
if (file_exists($directory . $class_name . '.php')) {
require_once ($directory . $class_name . '.php');
return;
}
}
}
I realize this is an older post BUT... DON'T INCLUDE YOUR CLASSES... instead use __autoload
function __autoload($class_name) {
require_once('classes/'.$class_name.'.class.php');
}
$user = new User();
Then whenever you call a new class that hasn't been included yet php will auto fire __autoload and include it for you
this is just a modification of Karsten's code
function include_all_php($folder){
foreach (glob("{$folder}/*.php") as $filename)
{
include $filename;
}
}
include_all_php("my_classes");
How to do this in 2017:
spl_autoload_register( function ($class_name) {
$CLASSES_DIR = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR; // or whatever your directory is
$file = $CLASSES_DIR . $class_name . '.php';
if( file_exists( $file ) ) include $file; // only include if file exists, otherwise we might enter some conflicts with other pieces of code which are also using the spl_autoload_register function
} );
Recommended by PHP documentation here: Autoloading classes
You can use set_include_path:
set_include_path('classes/');
http://php.net/manual/en/function.set-include-path.php
If there are NO dependencies between files... here is a recursive function to include_once ALL php files in ALL subdirs:
$paths = [];
function include_recursive( $path, $debug=false){
foreach( glob( "$path/*") as $filename){
if( strpos( $filename, '.php') !== FALSE){
# php files:
include_once $filename;
if( $debug) echo "<!-- included: $filename -->\n";
} elseif( is_dir($filename)) { # dirs
$paths[] = $filename;
}
}
# Time to process the dirs:
for( $i=count($paths)-1; $i>=0; $i--){
$path = $paths[$i];
unset( $paths[$i]);
include_recursive( $path, $debug);
}
}
include_recursive( "tree_to_include");
# or... to view debug in page source:
include_recursive( "tree_to_include", 'debug');
<?php
//Loading all php files into of functions/ folder
$folder = "./functions/";
$files = glob($folder."*.php"); // return array files
foreach($files as $phpFile){   
require_once("$phpFile");
}
If you want include all in a directory AND its subdirectories:
$dir = "classes/";
$dh = opendir($dir);
$dir_list = array($dir);
while (false !== ($filename = readdir($dh))) {
if($filename!="."&&$filename!=".."&&is_dir($dir.$filename))
array_push($dir_list, $dir.$filename."/");
}
foreach ($dir_list as $dir) {
foreach (glob($dir."*.php") as $filename)
require_once $filename;
}
Don't forget that it will use alphabetic order to include your files.
If your looking to include a bunch of classes without having to define each class at once you can use:
$directories = array(
'system/',
'system/db/',
'system/common/'
);
foreach ($directories as $directory) {
foreach(glob($directory . "*.php") as $class) {
include_once $class;
}
}
This way you can just define the class on the php file containing the class and not a whole list of $thisclass = new thisclass();
As for how well it handles all the files? I'm not sure there might be a slight speed decrease with this.
I suggest you use a readdir() function and then loop and include the files (see the 1st example on that page).
Try using a library for that purpose.
That is a simple implementation for the same idea I have build.
It include the specified directory and subdirectories files.
IncludeAll
Install it via terminal [cmd]
composer install php_modules/include-all
Or set it as a dependency in the package.json file
{
"require": {
"php_modules/include-all": "^1.0.5"
}
}
Using
$includeAll = requires ('include-all');
$includeAll->includeAll ('./path/to/directory');
This is a late answer which refers to PHP > 7.2 up to PHP 8.
The OP does not ask about classes in the title, but from his wording we can read that he wants to include classes. (btw. this method also works with namespaces).
By using require_once you kill three mosquitoes with one towel.
first, you get a meaningful punch in the form of an error message in your logfile if the file doesn't exist. which is very useful when debugging.( include would just generate a warning that might not be that detailed)
you include only files that contain classes
you avoid loading a class twice
spl_autoload_register( function ($class_name) {
require_once '/var/www/homepage/classes/' . $class_name . '.class.php';
} );
this will work with classes
new class_name;
or namespaces. e.g. ...
use homepage\classes\class_name;
Answer ported over from another question. Includes additional info on the limits of using a helper function, along with a helper function for loading all variables in included files.
There is no native "include all from folder" in PHP. However, it's not very complicated to accomplish. You can glob the path for .php files and include the files in a loop:
foreach (glob("test/*.php") as $file) {
include_once $file;
}
In this answer, I'm using include_once for including the files. Please feel free to change that to include, require or require_once as necessary.
You can turn this into a simple helper function:
function import_folder(string $dirname) {
foreach (glob("{$dirname}/*.php") as $file) {
include_once $file;
}
}
If your files define classes, functions, constants etc. that are scope-independent, this will work as expected. However, if your file has variables, you have to "collect" them with get_defined_vars() and return them from the function. Otherwise, they'd be "lost" into the function scope, instead of being imported into the original scope.
If you need to import variables from files included within a function, you can:
function load_vars(string $path): array {
include_once $path;
unset($path);
return get_defined_vars();
}
This function, which you can combine with the import_folder, will return an array with all variables defined in the included file. If you want to load variables from multiple files, you can:
function import_folder_vars(string $dirname): array {
$vars = [];
foreach (glob("{$dirname}/*.php") as $file) {
// If you want to combine them into one array:
$vars = array_merge($vars, load_vars($file));
// If you want to group them by file:
// $vars[$file] = load_vars($file);
}
return $vars;
}
The above would, depending on your preference (comment/uncomment as necessary), return all variables defined in included files as a single array, or grouped by the files they were defined in.
On a final note: If all you need to do is load classes, it's a good idea to instead have them autoloaded on demand using spl_autoload_register. Using an autoloader assumes that you have structured your filesystem and named your classes and namespaces consistently.
Do no write a function() to include files in a directory. You may lose the variable scopes, and may have to use "global". Just loop on the files.
Also, you may run into difficulties when an included file has a class name that will extend to the other class defined in the other file - which is not yet included. So, be careful.

Categories