php get namespace of included file - php

//file foo.php
<?php
namespace foo;
class foo{
function __construct(){
echo "hello";
}
}
?>
//file index.php
<?php
require_once("foo.php");
echo __NAMESPACE__;
?>
My question is, from my index.php file, is it possible to know what the namespace of foo.php is without reading the file contents and doing a regular expression on it? That just seems like a lot of overhead.
///EDIT
I'd really like to be able to dynamically add the namespace to the included file.
<?php
namespace dynamic;
require_once("foo.php");
echo __NAMESPACE__;
?>
I want to allow for third-party plugins, but php namespaces seems terrible. I don't want to have the plugin editors have to create a namespace.

No. But you could trick it this way round:
//file foo.php
<?php
namespace foo;
//...
return __NAMESPACE__; // must be last line
?>
And for reading it out:
//file index.php
<?php
$ns = require_once("foo.php");

Well, you could scan the class namespace. It contains namespaces. It's the PHPUnit way of doing things. So i.e.:
$namespaces = get_current_namespaces();
include 'plugin/main.php';
$newNamespaces = get_current_namespaces();
array_diff($namespaces, $newNamespaces)
Here is how you can implement get_current_namespaces(): is it possible to get list of defined namespaces

If you know the file, you can simply extract the namespace form it :).
function extract_namespace($file) {
$ns = NULL;
$handle = fopen($file, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
if (strpos($line, 'namespace') === 0) {
$parts = explode(' ', $line);
$ns = rtrim(trim($parts[1]), ';');
break;
}
}
fclose($handle);
}
return $ns;
}
And you will be not constrain to return something at the end of file that can be broke from exit or other return instructions.

I worked out the fairly laborious manual way to do this.
Like discussed at top the process itself is simple:
get your list of files for each file. Now for each file:
create a random namespace id
trim file and replace the first start tag
add namespace id and start tag to file
write to temp file
import temp file
do any reflection required then cleanup
I've got an example with some zend here.... probably not the most efficient but it works.
<?php
//first setup zend
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__)."/../zend/library/");
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace(dirname(__FILE__)."/../zend/library/");
//include my extender class
class Zend_Reflection_File_WithNamespace extends Zend_Reflection_File {
public function getFunctionsWithNamespace($namespace = '', $reflectionClass = 'Zend_Reflection_Function')
{
$functions = array();
foreach ($this->_functions as $function) {
$newName = $namespace . "\\" . $function;
$instance = new $reflectionClass($newName);
if (!$instance instanceof Zend_Reflection_Function) {
require_once 'Zend/Reflection/Exception.php';
throw new Zend_Reflection_Exception('Invalid reflection class provided; must extend Zend_Reflection_Function');
}
$functions[] = $instance;
}
return $functions;
}
}
//find file(s)
$startDir = 'hello/';
//$tempDir = 'php://temp/resource=';
$tempDir = 'temp/';
$fileList = scandir($startDir);
function ppPrintR($data) {
echo "<pre>";
print_r($data);
echo "</pre>";
}
//Now loop through each file, first writing to temp, including and then testing
foreach ($fileList as $key => &$fileItem) {
if (is_file($startDir . $fileItem)) {
//Take file and convert it
$findDir = $startDir . $fileItem;
echo $startDir . $fileItem;
$inContents = file_get_contents($findDir);
$randIden = 'm' . preg_replace('/\.|\s/', '', microtime());
//Replace the <?[php] at the start of the file with <? namespace xyz;
$inContents = trim($inContents);
$addString = 'namespace ' . $randIden . '; ';
$longTagPos = strpos($inContents,'<?php');
$shortTagPos = strpos($inContents,'<?');
if ($longTagPos !== false && $longTagPos < 10) {
$inContents = str_replace('<?php', '', $inContents);
$addString = '<?php ' . $addString;
}
else if ($shortTagPage !== false && $longTagPos < 10) {
$inContents = str_replace('<?', '', $inContents);
$addString = '<? ' . $addString;
}
$outContents = $addString . $inContents;
//Now write and require new temp file
$tempItem = $tempDir . $fileItem;
file_put_contents($tempItem, $outContents);
require($tempItem);
//Now do normal things
$reflectedFile = new Zend_Reflection_File_WithNamespace($tempItem);
echo 'Before<br/>';
$functions = $reflectedFile->getFunctionsWithNamespace($randIden);
echo 'After<br/>';
//Now foreach function, read params and consider execution
foreach($functions as &$functionItem) {
echo $functionItem->name . "<br/>";
$functionParams = $functionItem->getParameters();
ppPrintR($functionParams);
}
//FIXME should clean here
}
}
?>

Related

Get name of folder within glob method

I'm iterating with glob through my image-folder with nested folders to find images. The structure looks like this:
-> images
-> John Doe (some names)
-> 21-09-2018 (some dates)
-> 23-09-2018 (some dates)
Now I would like to get the name of 'name'-folder and the name of the 'date'-folder in which the image is. How can I get these in my existing loop and push it to my array?
$fileArray = [];
$path = 'http://example.com/demo';
foreach (glob("images/*/*/*.{jpg,JPG,jpeg,JPEG,png,PNG}", GLOB_BRACE) as $curFilename)
{
$completePath = $path . '/' . $curFilename;
$FilenameWithoutExt = preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($curFilename));
$basename = basename($curFilename);
if (strpos($FilenameWithoutExt, 'R') !== false) {
$eye = 'R';
}
else if (strpos($FilenameWithoutExt, 'L') !== false) {
$eye = 'L';
} else {
$eye = '';
}
$caption = $eye . ' - ' . date("d.m.Y");
$curFileObj = new mFile;
$curFileObj->caption = $caption;
$curFileObj->url = $completePath;
$curFileObj->thumbUrl = $completePath;
$curFileObj->date = date("d.m.Y");
$curFileObj->eye = $eye;
$curFileObj->basename = $basename;
array_push($fileArray, $curFileObj);
}
echo json_encode($fileArray);
SplFileInfo
You can just make a SplFileInfo object from file pathname.
For example:
$file = new SplFileInfo($curFilename);
echo $file->getPath();
will output path to your file.
There is more methods you can use, and I think you should find everything you need inside this object.
RecursiveIteratorIterator
There is also something like RecursiveIteratorIterator which will return array of SplFileInfo instead of just string pathnames like glob() does.
You can use it like:
$dir_iterator = new RecursiveDirectoryIterator('images/*/*/');
$iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
But inside you have to check extension if it is what you expect.
Manual
The SplFileInfo class
The RecursiveIteratorIterator class

Php simple algorithm for autoloader

Here's my "simple" algorithm:
if the class is named like 'AaaBbbCccDddEeeFff' loop like this:
include/aaa/bbb/ccc/ddd/eee/fff.php
include/aaa/bbb/ccc/ddd/eee_fff.php
include/aaa/bbb/ccc/ddd_eee_fff.php
include/aaa/bbb/ccc_ddd_eee_fff.php
include/aaa/bbb_ccc_ddd_eee_fff.php
include/aaa_bbb_ccc_ddd_eee_fff.php
if still nothing found, try to look if those files exist:
include/aaa/bbb/ccc/ddd/eee/fff/base.php
include/aaa/bbb/ccc/ddd/eee/base.php
include/aaa/bbb/ccc/ddd/base.php
include/aaa/bbb/ccc/base.php
include/aaa/bbb/base.php
include/aaa/base.php
include/base.php
If still not found then error.
I'm looking for a fast and easy way to convert this:
'AaaBbbCccDddEeeFff'
to this:
include/aaa/bbb/ccc/ddd/eee/fff.php
and then and easy way to remove latest folder (I guess I should look for explode()).
Any idea how to do this? (I'm not asking for the whole code, I'm not lazy).
Since you specifically asked not to have the whole code, here is some code to get you started. This takes the input and divides it into chunks delineated by changes in case. The rest you can work out as an exercise.
<?php
$input = "AaaBbbCccDddEeeFff";
$str_so_far = "";
$last_was_upper = 0;
$chunks = array();
while($next_letter = substr($input,0,1)) {
$is_upper = (strtoupper($next_letter)==$next_letter);
if($str_so_far && $is_upper && !$last_was_upper) {
$chunks[] = $str_so_far;
$str_so_far = "";
}
if($str_so_far && !$is_upper && $last_was_upper) {
$chunks[] = $str_so_far;
$str_so_far = "";
}
$str_so_far .= $next_letter;
$input = substr($input,1);
$last_was_upper = $is_upper;
}
var_dump($chunks);
?>
I think a regular expression would work. Something like preg_match_all('[A-Z][a-z][a-z]'
, $string); might work - that would match a capital letter, followed by a lowercase letter, and another lowercase letter.
As the other answers are regex, here's a non-regex way for completeness:
function transform($str){
$arr = array();
$part = '';
for($i=0; $i<strlen($str); $i++){
$char = substr($str, $i, 1);
if(ctype_upper($char) && $i > 0){
$arr[] = $part;
$part = '';
}
$part .= $char;
}
$arr[] = $part;
return 'include/' . strtolower(implode('/', $arr)) . '.php';
}
echo transform('AaaBbbCccDddEeeFff');
// include/aaa/bbb/ccc/ddd/eee/fff.php
This builds an array of the folders, so you can manipulate it as needed, for example remove a folder by unsetting the desired index, before it gets imploded.
Here is the first part of your algorithm:
AaaBbbCccDddEeeFff -> include/aaa/bbb/ccc/ddd/eee/fff.php
include/aaa/bbb/ccc/ddd/eee_fff.php
include/aaa/bbb/ccc/ddd_eee_fff.php
include/aaa/bbb/ccc_ddd_eee_fff.php
include/aaa/bbb_ccc_ddd_eee_fff.php
include/aaa_bbb_ccc_ddd_eee_fff.php
I think you can do last part independently based on my answer.
<?php
function convertClassToPath($class) {
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1' . DIRECTORY_SEPARATOR . '$2', $class)) . '.php';
}
function autoload($path) {
$base_dir = 'include' . DIRECTORY_SEPARATOR;
$real_path = $base_dir . $path;
var_dump('Checking: ' . $real_path);
if (file_exists($real_path) === true) {
var_dump('Status: Success');
include $real_path;
} else {
var_dump('Status: Fail');
$last_separator_pos = strrpos($path, DIRECTORY_SEPARATOR);
if ($last_separator_pos === false) {
return;
} else {
$path = substr_replace($path, '_', $last_separator_pos, 1);
autoload($path);
}
}
}
$class = 'AaaBbbCccDddEeeFff';
var_dump(autoload(convertClassToPath($class)));

Convert Variable to global in the class . . .php?

I need to send $user to inside the class and render function to make it global variable.
because it not work unless i write "$user" in the class and render function.
Please help me.
$user = 'admin';
class Template{
public function render($template_name)
{
global $user;
$path = $template_name . '.html';
if (file_exists($path))
{
$contents = file_get_contents($path);
function if_condition($matches)
{
$parts = explode(" ", $matches[0]);
$parts[0] = '<?PHP if(';
$parts[1] = '$' .$parts[1]; // $page
$parts[2] = ' ' . '==' . ' ';
$parts[3] = '"' . substr($parts[3], 0, -1) . '"'; //home
$allparts = $parts[0].$parts[1].$parts[2].$parts[3].') { ?>';
return $allparts.$gvar;
}
$contents = preg_replace_callback("/\[if (.*?)\]/", "if_condition", $contents);
$contents = preg_replace("/\[endif\]/", "<?PHP } ?>", $contents);
eval(' ?>' . $contents . '<?PHP ');
}
}
}
$template = new Template;
$template->render('test3');
Never, never use global variables
They are awful, they bind your code to context and they are side-effect - if you'll change your variable somewhere in 2054-th line of 119-th included file, the behavior of your application will change and then good luck with debugging that.
Instead you should either pass your user in method's parameters:
public function render($template_name, $user)
or create property in class instance:
class Template
{
protected $user = null;
public function render($template_name)
{
//access to $this->user instead of $user
}
//...
}
-and, of course, initialize $user property in class constructor.

Replace a string content with other content PHP

I have an a string declared at the top of my PHP script:
$dirname = "./rootfs/home/".$user."/";
After running the code, that string should be replace so it looks like this:
$dirname = "./rootfs/home/".$user."/testdir/";
Is there any way to replace the content? This is a dumb question for sure, but didn't found any way to do it, thanks! :D
Code I'm using:
Main PHP:
<?php
//Variables
$rootfs = "rootfs/";
$user = "www";
$dirname = "./rootfs/home/".$user."/";
//Variables
//Commands on rootfs/bin/
include($rootfs."/bin/ls.php");
include($rootfs."/bin/about.php");
include($rootfs."/bin/echo.php");
include($rootfs."/bin/uname.php");
include($rootfs."/bin/apt-get.php");
include($rootfs."/bin/whoami.php");
include($rootfs."/bin/cd.php");
//Commands on rootfs/bin/
$command=$_POST['command'];
$commandexp = explode(" ", $command);
switch ($commandexp[0]) {
case "cd":
//$dirname = "./rootfs/home/".$user."/";
//$prompt = cd($dirname, $commandexp[1]);
$dirname .= cd($dirname, $commandexp[1]);
echo $dirname;
break;
case "ls":
switch ($commandexp[1]) {
case "-la":
//$dirname = "./rootfs/home/".$user."/";
$files = ls($dirname);
foreach($files as $value){
$prompt .= substr(sprintf('%o', fileperms($dirname.$value)), -4)." ".$user." ".$value."<br>";
}
break;
case "--help":
$prompt = "Usage: ls [-la]";
break;
default:
echo $dirname." ";
$files = ls($dirname);
foreach($files as $value){
$prompt .= $value." ";
}
break;
}
break;
default:
$prompt = "command not found";
}
echo $prompt;
?>
The cd.php
<?php
function cd($actualdir, $dir) {
//echo $actualdir.$dir."<br>";
if(file_exists($actualdir.$dir)) {
echo $dir;
return $dir;
} else {
return "no";
}
}
?>
The ls.php
<?php
function ls ($directory) {
// create an array to hold directory list
$results = array();
// create a handler for the directory
$handler = opendir($directory);
echo $handler;
// open directory and walk through the filenames
while ($file = readdir($handler)) {
// if file isn't this directory or its parent, add it to the results
if ($file != "." && $file != "..") {
$results[] = $file;
}
}
// tidy up: close the handler
closedir($handler);
// done!
return $results;
}
?>
To add a string just do that:
$dirname .= "/testdir/";
To concatenate one string to the end of another string: $dirname .= 'testdir/'
To reassign a totally new string to the variable: $dirname = 'This is the new string'
See String Operators
Is this what you want:
$dirname .= "testdir/";
Finally used a session variable for storing the actual dir

replace string with PHP code

I need to find a string within a string ("foo", for example) and then replace it with a PHP code. Is it possible?
I'm creating a Joomla Plugin. When my article has something like "{foo}", i will replace it with an include (require, or whatever).
I've made something like:
public function onContentBeforeDisplay($context, &$row, &$params, $page=0)
{
// $row->text has the article text ...
if (preg_match('/{contact-form}/', $row->text))
{
require_once(dirname(__FILE__) . DS . 'tmpl' . DS . 'default.php');
}
}
But this code will insert default.php at the beginning. I want to replace it in {contact-form} tag.
Thank you.
You can use the PHP function "substr_replace()", whose details are given here.
\n";
/* These two examples replace all of $var with 'bob'. */
echo substr_replace($var, 'bob', 0) . "<br />\n";
echo substr_replace($var, 'bob', 0, strlen($var)) . "<br />\n";
/* Insert 'bob' right at the beginning of $var. */
echo substr_replace($var, 'bob', 0, 0) . "<br />\n";
/**
* Your food & search is here
*/
/* These next two replace 'MNRPQR' in $var with 'bob'. */
echo substr_replace($var, 'bob', 10, -1) . "<br />\n";
echo substr_replace($var, 'bob', -7, -1) . "<br />\n";
/* Delete 'MNRPQR' from $var. */
echo substr_replace($var, '', 10, -1) . "<br />\n";
?>
You can create a PHP file that matches the keyword (like: foo.php) and simply extract the keyword from the text and use it to include that file.
For example:
<?php
$str = "This is {foo} text";
$includePath = "/path/to/my/files/";
// Careful with the Regular Expression. If you allow chars like . in the
// keyword this could create a security problem. (Dots allow you to go backwards
// which would allow people to execute files outside your path.)
if (preg_match_all('/\{([\w]+)\}/', $str, $matches))
{
foreach ($matches[1] as $_match)
{
$filePath = $includePath . $_match . ".php";
if (file_exists($filePath))
{
include $filePath;
}
else
{
trigger_error("File does not exist '$filePath'.", E_USER_WARNING);
}
}
}
?>
I think you just want this, don't you?
<?php
$replacement = file_get_contents('myfile.php');
$content = str_replace('{foo}', eval($replacement), $content);
?>
If you need to replace any string on series of files on your remote server and well you don't have time for it! , here is your solution , I hope it can help someone.
////
//PHP 5.3 + Class find and replace string in files
//
//by Bruce Afruz
//
//2013
//
//example usage for single file:
//
//$new = new fileReplacement('./');
//$new->setExt("check.php");
//$new->changeContents("hello", "goodbye");
//
//example usage for multiple files:
//
//$new = new fileReplacement('./test');
//$new->setExt("*.html");
//$new->changeContents("hello", "goodbye");
//
//to change directory:
//
//$new = new fileReplacement('./test');
//$new->setDir("./test2");
//$new->setExt("*.html");
//$new->changeContents("hello", "goodbye");
////
class fileReplacement
{
private $ext , $dir ;
public function getDir() {
return $this->dir;
}
public function setDir($dir) {
$this->dir = $dir;
}
public function getExt() {
return $this->ext;
}
public function setExt($ext) {
$this->ext = $ext;
}
function __construct($dir) {
$this->dir = $dir;
}
public function rglob($pattern = '*', $flags = 0, $path = '') {
chdir($this->getDir());
$paths = glob($path . '*', GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);
$files = glob($path . $pattern, $flags);
foreach ($paths as $path) {
$files = array_merge($files, $this->rglob($pattern, $flags, $path));
}
return $files;
}
public function changeContents($replace , $sentence , $flags = 0, $path = '') {
$all = $this->rglob($this->getExt() , $flags, $path);
foreach ($all as $file) {
$filename = $file;
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$contents = str_replace($replace , $sentence, $contents);
if (is_writable($filename)) {
if (!$handle = fopen($filename, 'w+')) {
echo "Cannot open file ($filename)
";
exit;
}
// Write $contents to our opened file.
if (fwrite($handle, $contents) === FALSE) {
echo "Cannot write to file ($filename)
";
exit;
}
echo "Success, wrote content to file ($filename)
";
fclose($handle);
} else {
echo "The file $filename is not writable
";
}
}
}}

Categories