Integrate Composer with existing project autoloader - php

I'm updating a project and I've decided to update my Twig version. I deliberately haven't updated it in the past because of the fact you now need to use Composer, but I've eventually given in to this and decided to install a newer version.
However, it's messing around with my Autoload functions and not loading Twig properly, and I really don't want to have to use it. In a blank file with only the code to autoload Composer it works, so I know my autoloader is clashing. I can see that I'm going to have to use it to some degree, because Twig now requires it. I'm only interested in using it for third-party code, and I don't want to use it for anything else. So what I'm looking for is my own autoloader to try first, and then if I can't load a class by my own means, to try using the Composer autoloader. Third-party code exists in a subdirectory of "Lib". So With Twig, it sits in Lib/vendor/twig/twig/src.
At the moment, I'm checking the first part of the namespace and if it isn't matching my own, I'm trying to load the Composer autoload.php file in Lib/vendor/autoload.php, and then returning back out of my autoload function. But this doesn't seem to be finding the class.
Is what I'm trying to do actually possible? How would I approach something like this?
** Edit - Current Autoloader **
public static function autoloader($classname)
{
/* Separate by namespace */
$bits = explode('\\', ltrim($classname, '\\'));
$vendor = array_shift($bits);
/* If this doesn't belong to us, ignore it */
if ($vendor !== 'Site')
{
// We don't want to interfere here
if ($vendor == 'Forum')
return;
// Try to see if we can autoload with Composer, if not abort
include_once(SITE_ROOT.'include/Lib/vendor/autoload.php');
print_r(spl_autoload_functions ( ));
return;
}
$class = array_pop($bits);
$namespace = empty($bits) ? 'Site' : ('Site\\'.implode('\\', $bits));
$sources_dir = false;
$path = SITE_ROOT.'include/';
foreach (array_merge($bits, array($class)) as $i => $bit)
{
if ($i === 0 && $bit == 'Lib')
{
$bit = mb_strtolower($bit);
$sources_dir = true;
}
else if (preg_match("/^[a-z0-9]/", $bit)) // Applications only contain lowercase letters
{
if ($i === 0)
$path .= 'apps/';
else
$sources_dir = true;
}
else if ($i === 1 && ($bit == 'Api' || $bit == 'Cli' || $bit == 'Ajax')) // The API/CLI/AJAX interfaces have slightly different rules ....
{
$bit = mb_strtolower($bit);
$sources_dir = true;
}
else if ($sources_dir === false)
{
if ($i === 0)
{
$path .= 'components/';
}
else if ($i === 1 && $bit === 'Application')
{
// Do nothing
}
else
{
$path .= 'sources/';
}
$sources_dir = true;
}
$path .= $bit.'/';
}
/* Load it */
$path = \substr($path, 0, -1).'.php';
if (!file_exists($path))
{
$path = \substr($path, 0, -4).\substr($path, \strrpos($path, '/'));
if (!file_exists($path))
{
return false;
}
}
require_once($path);
if (interface_exists("{$namespace}\\{$class}", FALSE))
{
return;
}
/* Doesn't exist? */
if (!class_exists("{$namespace}\\{$class}", FALSE))
{
trigger_error("Class {$classname} could not be loaded. Ensure it has been properly prefixed and is in the correct namespace.", E_USER_ERROR);
}
}

It might be too late to load Composer's autoload.php within the custom autoload.
You should not worry too much about performance issues and just load both your custom autoloader and Composer's autoload one after to other. You can optimize a little by prioritizing these autoloaders based on which classes will you load more often (your own or those installed via Composer).
Also, your own/custom autoloader should only care about successful loading and not throw errors if something is not found. Leave that to PHP, this could help with compatibility with other autoloaders.

Related

Why Codeignitor does not accept autoload Controller classes when validating routes?

Why does Codeignitor not accept Controller in composer autoload when validating routes?
It's checking by: class_exists($class, FALSE) where the second parameter disables checking in autoload.
https://github.com/bcit-ci/CodeIgniter
$e404 = FALSE;
$class = ucfirst($RTR->class);
$method = $RTR->method;
if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
{
$e404 = TRUE;
}
else
{
require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');
if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
{
$e404 = TRUE;
}
elseif (method_exists($class, '_remap'))
{
$params = array($method, array_slice($URI->rsegments, 2));
$method = '_remap';
}
elseif ( ! method_exists($class, $method))
{
$e404 = TRUE;
}
/**
* DO NOT CHANGE THIS, NOTHING ELSE WORKS!
*
* - method_exists() returns true for non-public methods, which passes the previous elseif
* - is_callable() returns false for PHP 4-style constructors, even if there's a __construct()
* - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited
* - People will only complain if this doesn't work, even though it is documented that it shouldn't.
*
* ReflectionMethod::isConstructor() is the ONLY reliable check,
* knowing which method will be executed as a constructor.
*/
elseif ( ! is_callable(array($class, $method)))
{
$reflection = new ReflectionMethod($class, $method);
if ( ! $reflection->isPublic() OR $reflection->isConstructor())
{
$e404 = TRUE;
}
}
}
Looking over the git history, the change was introduced in 49e68de96b420a444c826995746a5f09470e76d9, with the commit message being:
Disable autoloader call from class_exists() occurences to improve performance
Note: The Driver libary tests seem to depend on that, so one occurence in CI_Loader is left until we resolve that.
So the nominal reason is performance.
If you want to ensure that the controller classes will be loaded on each request, you can add the files explicitly to the Composer autoload.files attribute, like so:
composer.json
{
"autoload": {
"files": [
"src/Foo.php"
]
},
"name": "test/64166739"
}
src/Foo.php
<?php
class Foo {}
test.php
<?php
$loader = require('./vendor/autoload.php');
var_dump(class_exists('Foo', false));
When run (via php test.php for example), we get the following output:
bool(true)
Additional
Looking over the code around that call to class_exists, it would appear that the controller files should follow a convention such that, for example with the built in Welcome controller and the default settings, the file that defines it should exist at:
application/controllers/Welcome.php
and so after require_onceing that file, the call to class_exists is a reasonably simple sanity check to ensure that the file did in fact define that class. So, based on this assumption about how controllers are added to the CodeIgniter application (ie all in the application/controllers directory and named the same as the class that they define), it's reasonable to bypass the autoloader when performing that check.
If you wanted to ensure the controllers are loaded when needed, the CodeIgniter way, they should be added to the application as listed above.

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.

Instantiating all classes in directory

I'm using Laravel and creating artisan commands but I need to register each one in start/artisan.php by calling
Artisan::add(new MyCommand);
How can I take all files in a directory (app/commands/*), and instantiate every one of them in an array ? I'd like to get something like (pseudocode) :
$my_commands = [new Command1, new Command2, new Command3];
foreach($my_commands as $command){
Artisan::add($command);
}
Here is a way to auto-register artisan commands. (This code was adapted from the Symfony Bundle auto-loader.)
function registerArtisanCommands($namespace = '', $path = 'app/commands')
{
$finder = new \Symfony\Component\Finder\Finder();
$finder->files()->name('*Command.php')->in(base_path().'/'.$path);
foreach ($finder as $file) {
$ns = $namespace;
if ($relativePath = $file->getRelativePath()) {
$ns .= '\\'.strtr($relativePath, '/', '\\');
}
$class = $ns.'\\'.$file->getBasename('.php');
$r = new \ReflectionClass($class);
if ($r->isSubclassOf('Illuminate\\Console\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) {
\Artisan::add($r->newInstance());
}
}
}
registerArtisanCommands();
If you put that in your start/artisan.php file, all commands found in app/commands will be automatically registered (assuming you follow Laravel's recommendations for command and file names). If you namespace your commands like I do, you can call the function like so:
registerArtisanCommands('App\\Commands');
(This does add a global function, and a better way to do this would probably be creating a package. But this works.)
<?php
$contents = scandir('dir_path');
$files = array();
foreach($contents as $content) {
if(substr($content,0,1 == '.') {
continue;
}
$files[] = 'dir_path'.$content;
}
That reads the contents of a folder, itterates over it and saves the filename including path in the $files array. Hope this is what you're looking for
PS: Im not familiar with laravel or artisan. So if you have to use specific semantics(like camelCase) to register them, then please tell me so

phpfastcache unlink() permission denied

I'm using phpfastcache https://github.com/khoaofgod/phpfastcache/
when I try to delete the cache I get an error
Warning: unlink(C:\...//sqlite/indexing): Permission denied in C:\...drivers\sqlite.php on line 328
I usually see that kind of error when there is a process not releasing the handle of those files.
Step to reproduce
// Require phpfastcache
require_once 'phpfastcache_v2.1_release\phpfastcache\phpfastcache.php';
// Simple singleton
class MyCache extends phpFastCache
{
private static $istance;
Private $obCache;
function __construct()
{
$option = array('securityKey' => 'aCache', 'path' => dirname(__FILE__));
$this->obCache = parent::__construct('sqlite', $option);
}
public static function getIstance()
{
if( is_null(self::$istance) )
{
self::$istance = new self();
}
return self::$istance;
}
}
// check if cached
if( $CacheData = MyCache::getIstance()->get('aKeyword') )
{
die('Cached');
}
// store in cache
MyCache::getIstance()->set('aKeyword','aValue', 60*60*24);
// clean cache (throw error)
MyCache::getIstance()->clean();
die('No cached');
this is the method of "phpfastcache" that generates the error
function driver_clean($option = array()) {
// delete everything before reset indexing
$dir = opendir($this->path);
while($file = readdir($dir)) {
if($file != "." && $file!="..") {
unlink($this->path."/".$file);
}
}
}
does anyone know how to fix this?
I'm temporarily using #unlink()
I tried but nothing has changed
chmod($this->path."/".$file, 0777);
unlink($this->path."/".$file);
UPDATE
I'm under windows...
UPDATE 2
I installed XAMPP using the admin account, after installation run with admin privileges...
UPDATE 3
Solution:
function driver_clean($option = array()) {
// close connection
$this->instant = array();
$this->indexing = NULL;
// delete everything before reset indexing
$dir = opendir($this->path);
while($file = readdir($dir)) {
if($file != "." && $file!="..") {
unlink($this->path."/".$file);
}
}
}
The solution depends on the environment that serves the script.
If it's CLI, the ability to creating, deleting or modifing files are controlled by the executing user.
If it's a PHP Stack ( WAMP, XAMPP, ZendServer or own Webserver+PHP+MySQL-Stack ) the executing layer ( apache, nginx ) must use an user which has rights to do what you want to do.
In both cases it depends on what you've configured or what had been inherited to your script, directory or drive.
Permission Knowledge could be found here: http://technet.microsoft.com/en-us/library/cc770962.aspx
(Doesn't work under Windows) Try to change permissions before:
chmod($yourfile, '0777');
unlink($yourfile);

CodeIgniter Checking Files

I'm writing a template_loader for my CodeIgniter project. As usual, I need several security layers for my templates. One of them, which is the very first one, is checking if the files exists or not.
Now, My Problem is: I can't configure what address to give to the template loader. When I use simple php function called 'include()', it works, but with my template_loader function, it fails to work.
Here is my actual page (index.php):
<?php
/**
Add the page-suitable template from in folder.
**/
$this->template_loader->load_template('inc/temp_one_col.php');
// include('inc/temp_one_col.php');
?>
And here is my class and template_loader:
class Template_loader
{
function load_template ($arg)
{
$base_name = basename($arg);
$CI =& get_instance();
if(file_exists($arg) === true)
{
echo 'it is also good.';
if (pathinfo($base_name, PATHINFO_EXTENSION) == 'php' ||
pathinfo($base_name, PATHINFO_EXTENSION) == 'html'
)
{
$file_name_check = substr($base_name, 0, 4);
if($file_name_check === TEMP_FILE_INDICATOR)
{
include($arg);
}
else
{
redirect($CI->base_url . '/error/show_problem');
}
}
else
{
redirect($CI->base_url . '/error/show_problem');
}
}
else
{
redirect($CI->base_url . '/error/show_problem');
}
}
}
Out of interest, what are you passing to the function as the $arg parameter?
Sounds like you just need to use the correct path to the file, which should be the absolute path to the file in the filesystem.
To get the absolute path you could create a new global variable in your sites index.php to point to your views folder.
webroot/index.php:
if (realpath('../application/views') !== FALSE)
{
$views_path =realpath('../application/views').'/';
define('VIEWSPATH', $views_path);
}
Now you can use this as the base for your $arg parameter VIEWSPATH.$path_to_file

Categories