I have a php file which contains only one class. how can I know what class is there by knowing the filename? I know I can do something with regexp matching but is there a standard php way? (the file is already included in the page that is trying to figure out the class name).
There are multiple possible solutions to this problem, each with their advantages and disadvantages. Here they are, it's up to know to decide which one you want.
Tokenizer
This method uses the tokenizer and reads parts of the file until it finds a class definition.
Advantages
Do not have to parse the file entirely
Fast (reads the beginning of the file only)
Little to no chance of false positives
Disadvantages
Longest solution
Code
$fp = fopen($file, 'r');
$class = $buffer = '';
$i = 0;
while (!$class) {
if (feof($fp)) break;
$buffer .= fread($fp, 512);
$tokens = token_get_all($buffer);
if (strpos($buffer, '{') === false) continue;
for (;$i<count($tokens);$i++) {
if ($tokens[$i][0] === T_CLASS) {
for ($j=$i+1;$j<count($tokens);$j++) {
if ($tokens[$j] === '{') {
$class = $tokens[$i+2][1];
}
}
}
}
}
Regular expressions
Use regular expressions to parse the beginning of the file, until a class definition is found.
Advantages
Do not have to parse the file entirely
Fast (reads the beginning of the file only)
Disadvantages
High chances of false positives (e.g.: echo "class Foo {";)
Code
$fp = fopen($file, 'r');
$class = $buffer = '';
$i = 0;
while (!$class) {
if (feof($fp)) break;
$buffer .= fread($fp, 512);
if (preg_match('/class\s+(\w+)(.*)?\{/', $buffer, $matches)) {
$class = $matches[1];
break;
}
}
Note: The regex can probably be improved, but no regex alone can do this perfectly.
Get list of declared classes
This method uses get_declared_classes() and look for the first class defined after an include.
Advantages
Shortest solution
No chance of false positive
Disadvantages
Have to load the entire file
Have to load the entire list of classes in memory twice
Have to load the class definition in memory
Code
$classes = get_declared_classes();
include 'test2.php';
$diff = array_diff(get_declared_classes(), $classes);
$class = reset($diff);
Note: You cannot simply do end() as others suggested. If the class includes another class, you will get a wrong result.
This is the Tokenizer solution, modified to include a $namespace variable containing the class namespace, if applicable:
$fp = fopen($file, 'r');
$class = $namespace = $buffer = '';
$i = 0;
while (!$class) {
if (feof($fp)) break;
$buffer .= fread($fp, 512);
$tokens = token_get_all($buffer);
if (strpos($buffer, '{') === false) continue;
for (;$i<count($tokens);$i++) {
if ($tokens[$i][0] === T_NAMESPACE) {
for ($j=$i+1;$j<count($tokens); $j++) {
if ($tokens[$j][0] === T_STRING) {
$namespace .= '\\'.$tokens[$j][1];
} else if ($tokens[$j] === '{' || $tokens[$j] === ';') {
break;
}
}
}
if ($tokens[$i][0] === T_CLASS) {
for ($j=$i+1;$j<count($tokens);$j++) {
if ($tokens[$j] === '{') {
$class = $tokens[$i+2][1];
}
}
}
}
}
Say you have this class:
namespace foo\bar {
class hello { }
}
...or the alternative syntax:
namespace foo\bar;
class hello { }
You should have the following result:
var_dump($namespace); // \foo\bar
var_dump($class); // hello
You could also use the above to detect the namespace a file declares, regardless of it containing a class or not.
You can make PHP do the work by just including the file and get the last declared class:
$file = 'class.php'; # contains class Foo
include($file);
$classes = get_declared_classes();
$class = end($classes);
echo $class; # Foo
If you need to isolate that, wrap it into a commandline script and execute it via shell_exec:
$file = 'class.php'; # contains class Foo
$class = shell_exec("php -r \"include('$file'); echo end(get_declared_classes());\"");
echo $class; # Foo
If you dislike commandline scripts, you can do it like in this question, however that code does not reflect namespaces.
I modified Nette\Reflection\AnnotationsParser that so it returns an array of namespace+classname that are defined in the file
$parser = new PhpParser();
$parser->extractPhpClasses('src/Path/To/File.php');
class PhpParser
{
public function extractPhpClasses(string $path)
{
$code = file_get_contents($path);
$tokens = #token_get_all($code);
$namespace = $class = $classLevel = $level = NULL;
$classes = [];
while (list(, $token) = each($tokens)) {
switch (is_array($token) ? $token[0] : $token) {
case T_NAMESPACE:
$namespace = ltrim($this->fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
break;
case T_CLASS:
case T_INTERFACE:
if ($name = $this->fetch($tokens, T_STRING)) {
$classes[] = $namespace . $name;
}
break;
}
}
return $classes;
}
private function fetch(&$tokens, $take)
{
$res = NULL;
while ($token = current($tokens)) {
list($token, $s) = is_array($token) ? $token : [$token, $token];
if (in_array($token, (array) $take, TRUE)) {
$res .= $s;
} elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], TRUE)) {
break;
}
next($tokens);
}
return $res;
}
}
$st = get_declared_classes();
include "classes.php"; //one or more classes in file, contains class class1, class2, etc...
$res = array_values(array_diff_key(get_declared_classes(),$st));
print_r($res); # Array ([0] => class1 [1] => class2 [2] ...)
Thanks to some people from Stackoverflow and Github, I was able to write this amazing fully working solution:
/**
* get the full name (name \ namespace) of a class from its file path
* result example: (string) "I\Am\The\Namespace\Of\This\Class"
*
* #param $filePathName
*
* #return string
*/
public function getClassFullNameFromFile($filePathName)
{
return $this->getClassNamespaceFromFile($filePathName) . '\\' . $this->getClassNameFromFile($filePathName);
}
/**
* build and return an object of a class from its file path
*
* #param $filePathName
*
* #return mixed
*/
public function getClassObjectFromFile($filePathName)
{
$classString = $this->getClassFullNameFromFile($filePathName);
$object = new $classString;
return $object;
}
/**
* get the class namespace form file path using token
*
* #param $filePathName
*
* #return null|string
*/
protected function getClassNamespaceFromFile($filePathName)
{
$src = file_get_contents($filePathName);
$tokens = token_get_all($src);
$count = count($tokens);
$i = 0;
$namespace = '';
$namespace_ok = false;
while ($i < $count) {
$token = $tokens[$i];
if (is_array($token) && $token[0] === T_NAMESPACE) {
// Found namespace declaration
while (++$i < $count) {
if ($tokens[$i] === ';') {
$namespace_ok = true;
$namespace = trim($namespace);
break;
}
$namespace .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i];
}
break;
}
$i++;
}
if (!$namespace_ok) {
return null;
} else {
return $namespace;
}
}
/**
* get the class name form file path using token
*
* #param $filePathName
*
* #return mixed
*/
protected function getClassNameFromFile($filePathName)
{
$php_code = file_get_contents($filePathName);
$classes = array();
$tokens = token_get_all($php_code);
$count = count($tokens);
for ($i = 2; $i < $count; $i++) {
if ($tokens[$i - 2][0] == T_CLASS
&& $tokens[$i - 1][0] == T_WHITESPACE
&& $tokens[$i][0] == T_STRING
) {
$class_name = $tokens[$i][1];
$classes[] = $class_name;
}
}
return $classes[0];
}
You can do this in two ways:
complex solution: open the file and through regex extract the class-name (like /class ([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/)
simply solution: name all your php files with the class-name contained (eg: the class TestFoo in the file TestFoo.php or TestFoo.class.php)
You could get all declared classes before you include the file using get_declared_classes. Do the same thing after you have included it and compare the two with something like array_diff and you have your newly added class.
This sample returns all classes. If you're looking for a class which is derived of a specific one, use is_subclass_of
$php_code = file_get_contents ( $file );
$classes = array ();
$namespace="";
$tokens = token_get_all ( $php_code );
$count = count ( $tokens );
for($i = 0; $i < $count; $i ++)
{
if ($tokens[$i][0]===T_NAMESPACE)
{
for ($j=$i+1;$j<$count;++$j)
{
if ($tokens[$j][0]===T_STRING)
$namespace.="\\".$tokens[$j][1];
elseif ($tokens[$j]==='{' or $tokens[$j]===';')
break;
}
}
if ($tokens[$i][0]===T_CLASS)
{
for ($j=$i+1;$j<$count;++$j)
if ($tokens[$j]==='{')
{
$classes[]=$namespace."\\".$tokens[$i+2][1];
}
}
}
return $classes;
I spent lots of productive time looking for a way around this.
From #netcoder's solution its obvious there are lots of cons in all the solutions so far.
So I decided to do this instead.
Since most PHP classes has class name same as filename, we could get the class name from the filename. Depending on your project you could also have a naming convention.
NB: This assume class does not have namespace
<?php
$path = '/path/to/a/class/file.php';
include $path;
/*get filename without extension which is the classname*/
$classname = pathinfo(basename($path), PATHINFO_FILENAME);
/* you can do all this*/
$classObj = new $classname();
/*dough the file name is classname you can still*/
get_class($classObj); //still return classname
Let me add a PHP 8 compatible solution as well. This will scan a file accordingly and return all FQCN's:
$file = 'whatever.php';
$classes = [];
$namespace = '';
$tokens = PhpToken::tokenize(file_get_contents($file));
for ($i = 0; $i < count($tokens); $i++) {
if ($tokens[$i]->getTokenName() === 'T_NAMESPACE') {
for ($j = $i + 1; $j < count($tokens); $j++) {
if ($tokens[$j]->getTokenName() === 'T_NAME_QUALIFIED') {
$namespace = $tokens[$j]->text;
break;
}
}
}
if ($tokens[$i]->getTokenName() === 'T_CLASS') {
for ($j = $i + 1; $j < count($tokens); $j++) {
if ($tokens[$j]->getTokenName() === 'T_WHITESPACE') {
continue;
}
if ($tokens[$j]->getTokenName() === 'T_STRING') {
$classes[] = $namespace . '\\' . $tokens[$j]->text;
} else {
break;
}
}
}
}
// Contains all FQCNs found in a file.
$classes;
You may be able to use the autoload function.
function __autoload($class_name) {
include "special_directory/" .$class_name . '.php';
}
And you can echo $class_name. But that requires a directory with a single file.
But it is standard practice to have one class in each file in PHP. So Main.class.php will contain Main class. You may able to use that standard if you are the one coding.
Related
Im trying to get the number of class and methods in a specific directory which contain sub folder and scan through them. So far I can only count the number of files.
$ite=new RecursiveDirectoryIterator("scanME");
//keyword search
$classWords = array('class');
$functionWords = array('function');
//Global Counts
$bytestotal=0;
$nbfiles=0;
$classCount = 0;
$methodCount = 0;
foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) {
$filesize=$cur->getSize();
$bytestotal+=$filesize;
if(is_file($cur))
{
$nbfiles++;
foreach ($classWords as $classWord) {
$fileContents = file_get_contents($cur);
$place = strpos($fileContents, $classWord);
if (!empty($place)) {
$classCount++;
}
}
foreach($functionWords as $functionWord) {
$fileContents = file_get_contents($cur);
$place = strpos($fileContents, $functionWord);
if (!empty($place)) {
$methodCount++;
}
}
}
}
EDIT: I manage to count the keyword class and function but the problem is it only concatenate for each file. Eg: I have 2 class in one file it will just count 1. How do I count for each keyword in a file?
The only time you define $classContents is at the top where you're attempting to get the contents of the directory:
$classContents = file_get_contents('scanMeDir');
You should be getting the contents of each file while looping through the RecursiveDirectoryIterator results. (You also don't need to create a new iterator instance):
foreach ($ite as $filename => $cur) {
$classContents = file_get_contents($filename);
...
}
using token instead of keyword is the better solution for this
$bytestotal=0;
$nbfiles=0;
$fileToString;
$token;
$pathInfo;
$classCount = 0;
$methodCount = 0;
foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) {
$filesize=$cur->getSize();
$bytestotal+=$filesize;
if(is_file($cur))
{
$nbfiles++;
$fileToString = file_get_contents($cur);
$token = token_get_all($fileToString);
$tokenCount = count($token);
//Class Count
$pathInfo = pathinfo($cur);
if ($pathInfo['extension'] === 'php') {
for ($i = 2; $i < $tokenCount; $i++) {
if ($token[$i-2][0] === T_CLASS && $token[$i-1][0] === T_WHITESPACE && $token[$i][0] === T_STRING ) {
$classCount++;
}
}
} else {
error_reporting(E_ALL & ~E_NOTICE);
}
//Method Count
for ($i = 2; $i < $tokenCount; $i++) {
if ($token[$i-2][0] === T_FUNCTION && $token[$i-1][0] === T_WHITESPACE && $token[$i][0] === T_STRING) {
$methodCount++;
}
}
}
}
How to get relative filename from absolute one and some given path?
For example:
foo('/a/b/c/1.txt', '/a/d/e'); // '../../b/c/1.txt'
foo('/a/b/../d/1.txt', '/a/d/e'); // '../c/1.txt'
Is there some native function for this?
My thoughts, if there is not:
Normalize both params: need to use some realpath replacement, because files can to not exist. example
Cut common parts from both
add rest parts from $basepath as '..'
Manual way looks too heavy for that common task..
For now, I assume there is not any native implementation and want to share my implementation of this.
/**
* realpath analog without filesystem check
*/
function str_normalize_path(string $path, string $sep = DIRECTORY_SEPARATOR): string {
$parts = array_filter(explode($sep, $path));
$stack = [];
foreach ($parts as $part) {
switch($part) {
case '.': break;
case '..': array_pop($stack); break; // excess '..' just ignored by array_pop([]) silency
default: array_push($stack, $part);
}
}
return implode($sep, $stack);
}
function str_relative_path(string $absolute, string $base, string $sep = DIRECTORY_SEPARATOR) {
$absolute = str_normalize_path($absolute);
$base = str_normalize_path($base);
// find common prefix
$prefix_len = 0;
for ($i = 0; $i < min(mb_strlen($absolute), mb_strlen($base)); ++$i) {
if ($absolute[$i] !== $base[$i]) break;
$prefix_len++;
}
// cut common prefix
if ($prefix_len > 0) {
$absolute = mb_substr($absolute, $prefix_len);
$base = mb_substr($base, $prefix_len);
}
// put '..'s for exit to closest common path
$base_length = count(explode($sep, $base));
$relative_parts = explode($sep, $absolute);
while($base_length-->0) array_unshift($relative_parts, '..');
return implode($sep, $relative_parts);
}
$abs = '/a/b/../fk1/fk2/../.././d//proj42/1.txt';
$base = '/a/d/fk/../e/f';
echo str_relative_path($abs, $base); // ../../proj42/1.txt
Just started to work with Propel 2.0 ORM. All tutorials are telling to work with schemas this way:
Create schema in XML/JSON/YAML/PHP file;
Run $ propel model:build
How do I create, or re-create, or update models and data without using the command line but just inside the php scripts? It might be necessary for creating CMS module installers or something like this.
The Answer: Commander Class
A «Reinvent-The-Wheel» approach but I did not found any other way to work with Propel 2 without CLI.
use Propel\Runtime\Propel;
use Propel\Generator\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Application;
/**
* Class Commander
*
* A script-based approach to run Propel commands without the CLI.
*
* Usage:
*
* ```
* $cmd = new Commander('<propel_command>', '<command_arguments>');
* $cmd->run();
* ...
* $cmd->addCommand('<propel_command>', '<command_arguments>');
* $cmd->run();
* ```
*
* In case of migration tasks you must call
* ```
* ...->preMigrate(array('<path_to_schema_files_dir1>', ..., '<path_to_schema_files_dirN>'), '<temp_dir>');
* ```
* to gather all schemas together and analyze 'em with propel:diff.
*
* Then after the diff and migrate are complete you must call ``postMigrate()`` to remove temporary
* schema copies.
*
*/
class Commander
{
private $command,
$parameters,
$migrationTempSource;
public function __construct($cmd = '', $params = '')
{
$this->addCommand($cmd, $params);
}
/**
* Prepare schema files to be analyzed before the migration process.
* #param array $schemaDirs Array of strings with schema directories
* #param string $tmpSchemaDir Temporary directory to copy schemas to.
* This path also must be used as a --schema-dir option value during the
* diff and migrate tasks
* #return boolean $result
*/
public function preMigrate($schemaDirs = array(), $tmpSchemaDir)
{
$result = false;
$filelist = [];
foreach($schemaDirs as $path)
{
if(is_dir($path))
{
$f = $this->seekFiles($path);
$filelist = count($f) > 0 ? array_merge($filelist, $f) : $f;
}
}
if(!file_exists($tmpSchemaDir))
{
mkdir($tmpSchemaDir, 0777, true);
}
foreach($schemaDirs as $path)
{
if(is_dir($path))
{
$f = $this->seekFiles($path);
foreach($f as $file)
{
copy($path . '/' . $file, $tmpSchemaDir . '/' . $file);
}
}
}
$this->migrationTempSource = $tmpSchemaDir;
return $result;
}
/**
* Removes the temporary schema files after the diff and migrate tasks are complete.
*
* #param bool $removeTmpDir Set to true if you want to remove the whole temporary
* directory, not just the schema files.
* #return bool
*/
public function postMigrate($removeTmpDir = false)
{
$result = false;
$dir = scandir($this->migrationTempSource);
foreach($dir as $d)
{
if($d != '.' && $d != '..')
{
unlink($this->migrationTempSource . '/' . $d);
}
}
if($removeTmpDir === true)
{
#rmdir($this->migrationTempSource);
}
return $result;
}
private function seekFiles($dir)
{
$res = [];
if(is_dir($dir))
{
$d = scandir($dir);
foreach($d as $dd)
{
if($dd != '.' && $dd != '..')
{
if((strpos($dd, 'schema.xml') == strlen($dd)-10) || ($dd == 'schema.xml'))
{
$res[] = $dd;
}
}
}
}
return $res;
}
public function addCommand($cmd = '', $params = '')
{
$this->command = $cmd;
$this->parameters = explode(' --', $params);
}
public function run()
{
if($this->command == '') return false;
$callCommandClass = '';
$cmdParts = explode(':', $this->command);
switch($cmdParts[0])
{
case 'config':
switch($cmdParts[1])
{
case 'convert':
$callCommandClass = 'ConfigConvertCommand';
break;
}
break;
case 'diff':
$callCommandClass = 'MigrationDiffCommand';
break;
case 'migration':
switch($cmdParts[1])
{
case 'create':
$callCommandClass = 'MigrationCreateCommand';
break;
case 'diff':
$callCommandClass = 'MigrationDiffCommand';
break;
case 'up':
$callCommandClass = 'MigrationUpCommand';
break;
case 'down':
$callCommandClass = 'MigrationDownCommand';
break;
case 'status':
$callCommandClass = 'MigrationStatusCommand';
break;
case 'migrate':
$callCommandClass = 'MigrationMigrateCommand';
break;
}
break;
case 'model':
switch($cmdParts[1])
{
case 'build':
$callCommandClass = 'ModelBuildCommand';
break;
}
break;
case 'sql':
switch($cmdParts[1])
{
case 'build':
$callCommandClass = 'SqlBuildCommand';
break;
case 'insert':
$callCommandClass = 'SqlInsertCommand';
break;
}
break;
}
$a = [];
foreach($this->parameters as $p)
{
$x = explode('=', $p);
if(count($x) > 1)
{
$a['--'.str_replace('--', '', $x[0])] = trim($x[1]);
}
else
{
$a['--'.str_replace('--', '', $x[0])] = true;
}
}
$commandLine = array('command' => $this->command) + $a;
$app = new Application('Propel', Propel::VERSION);
$cls = '\Propel\Generator\Command'.'\\'.$callCommandClass;
/** #noinspection PhpParamsInspection */
$app->add(new $cls());
$app->setAutoExit(false);
$output = new StreamOutput(fopen("php://temp", 'r+'));
$result = $app->run(new ArrayInput($commandLine), $output);
if(0 !== $result)
{
rewind($output->getStream());
return stream_get_contents($output->getStream());
}
else
{
return true;
}
}
}
And the usage example:
//Convert the configuration file
$cmd = new Commander('config:convert', '--config-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/config --output-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/config');
$cmd->run();
//... or (re)build models
$cmd = new Commander('model:build', '--schema-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/module/schema --output-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/module/models');
$cmd->run();
//... or perform database migration (actually not tested yet :/ )
$cmd = new Commander('migration:diff', '--schema-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/cache/schemacache');
$cmd->preMigrate([$_SERVER['DOCUMENT_ROOT'].'/propeltest/schema', $_SERVER['DOCUMENT_ROOT'].'/propeltest/module/schema'], $_SERVER['DOCUMENT_ROOT'].'/propeltest/cache/schemacache');
$cmd->run(); // runs migrate:diff
$cmd->addCommand('migration:diff', '--schema-dir='.$_SERVER['DOCUMENT_ROOT'].'/propeltest/cache/schemacache'); // prepare to actually migration
$cmd->run(); // perform migration:migrate
$cmd->postMigrate();
I'm taking data from an excel using phpexcel, like this:
$number = $objPHPExcel->getActiveSheet()->getCell('A3')->getValue();
number is clearly a number, okay? so, after that I want to know if $number exists on the word $elem:
if(strpos($elem,$number) !== false) //está?
{
$answer = true;
}
the problem is that when I test it with this data, the $answer is true, and it shouldn't be:
$number = 11001456
$elem = '10001033.jpg'
So... what's wrong here?
PD: I'm going to post the entire code so you can see it, If I try to do (string)$number then the code crashes, it exceeds time execution.... (using cakephp)
The important thing is located at the function SearchPhoto... you will see the strpos there...
public function admin_load() //esto sirve para cargar un excel...
{
if($this->request->is('post'))
{
$data = $this->request->data;
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
define('EOL',(PHP_SAPI == 'cli') ? PHP_EOL : '<br />');
date_default_timezone_set('Europe/London');
/** Include PHPExcel_IOFactory */
require_once WWW_ROOT . '/excelWorker/Classes/PHPExcel/IOFactory.php';
echo date('H:i:s') , " Load from Excel2007 file" , EOL;
$callStartTime = microtime(true);
$objPHPExcel = PHPExcel_IOFactory::load($data['People']['excel']['tmp_name']);
$dir = WWW_ROOT . "img/photos";
$files = scandir($dir);
$batchPeople = array();
for($i = 2; $i <= $data['People']['num']; $i++)
{
$batchPeople[$i-2]['People']['fullname'] = $objPHPExcel->getActiveSheet()->getCell('B'.$i)->getValue();
$batchPeople[$i-2]['People']['floor'] = $objPHPExcel->getActiveSheet()->getCell('C'.$i)->getValue();
$batchPeople[$i-2]['People']['country'] = $objPHPExcel->getActiveSheet()->getCell('D'.$i)->getValue();
$batchPeople[$i-2]['People']['day'] = $objPHPExcel->getActiveSheet()->getCell('F'.$i)->getValue();
$batchPeople[$i-2]['People']['month'] = $objPHPExcel->getActiveSheet()->getCell('G'.$i)->getValue();
$batchPeople[$i-2]['People']['photo'] = $this->SearchPhoto($objPHPExcel->getActiveSheet()->getCell('A'.$i)->getValue(),$files);
}
// $this->People->saveMany($batchPeople);
}
}
function SearchPhoto($number, $array)
{
$answer = '';
$getOut = false;
foreach($array as $elem)
{
if(strcmp($elem,'.') != 0 && strcmp($elem,'..') != 0)
if(strpos($elem,$number) !== false) //está?
{
echo 'coinciden--> '. $number . ',' . $elem;
echo '<br>';
$answer = $elem;
$getOut = true;
}
if($getOut)
break;
}
return $answer;
}
This should work for you:
(BTW: You use $number in the code and not $num)
<?php
$num = 11001456;
$elem = "10001033.jpg";
if(strpos($elem, (string)$num) !== false) {
echo "yes";
}
?>
For more information about strpos() look into the manual: http://php.net/manual/en/function.strpos.php
And a quote from there:
needle:
If needle is not a string, it is converted to an integer and applied as the ordinal value of a character.
echo chr($number); // p
echo strpos($elem, 'p'); // 10 (which is p in $elem)
I ended up using preg_match to solve my problem... I still don't know what's wrong with using strpos... because it works on all the sites I made expect this particular case!
In case anyone wondering what's the exact solution:
$text = $B;
$pattern = '/'.$A.'/';
preg_match($pattern,$text,$matches);
if(isset($matches[0]))
$answer = true;
This might be quite simple but I am stumped . Here is what I am trying to do load a csv file into a an entity . I found a php plugin but couldn't figure out how to install so I downloaded the plugin and took the script to read a csv file into my bundle Acme\StoreBundle and actually placed the script (sfCsvReader.php) in the entity folder in the bundle when I attempt to run this on the web I get the following error
Fatal error: Class 'Acme\StoreBundle\Controller\sfCsvReader' not found in /home/jan/symfonysandbox/src/Acme/StoreBundle/Controller/LoadCSVController.php on line 26
My Controller file is as follows
<?php
namespace Acme\StoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Acme\StoreBundle\Entity\Congress;
use Acme\StoreBundle\Entity\sfCsvReader;
use Symfony\Component\HttpFoundation\Response;
class LoadCSVController extends Controller
{
/**
* #Route("/load/{name}")
* #Template()
*/
public function indexAction()
{
$congress = new Congress();
$path = '~/Documents/congress.csv';
$reader = new sfCsvReader($path);
$reader->setSelectColumns('column_A, column_B');
$reader->open();
while ($data = $reader->read())
{
$congress->setTitle($data['column_A']);
$congress->setName($data['column_B']);
$em = $this->getDoctrine()->getManager();
$em->persist($congress);
$em->flush();
return new Response('Created congress id '.$congress->getId() .'for'.$congress->getTitle().'for'.$congress->getName());
}
$reader->close();
}
}
the script its calling is
sfCsvReader
<?php
namespace Acme\StoreBundle\Controller;
/**
* sfCsvReader
* by Carlos Escribano <carlos#markhaus.com>
*
* $csv = new sfCsvReader("/path/to/a/csv/file.csv");
* $csv->open();
* $csv->setSelectColumns('field_A, field_B'); // or array('field_A', 'field_B')
* while ($data = $csv->read())
* {
* // do something with $data['field_A'] and $data['field_B']
* }
* $csv->close();
*
* --- Alternative ---
* $csv = new sfCsvReader("/path/to/a/csv/file.csv");
* $csv->setSelectColumns('field_A, field_B'); // or array('field_A', 'field_B')
* $csv->open();
* ...
* --- Alternative: NUMERICAL INDEXES ---
* $csv = new sfCsvReader("/path/to/a/csv/file.csv");
* $csv->open();
* while ($data = $csv->read())
* {
* // do something with $data[0] and $data[1]
* }
* $csv->close();
*
*
* --- CHARSET ---
* $to = 'ISO-8859-1';
* $from = 'UTF-8';
* $csv->setCharset($to);
* $csv->setCharset($to, $from);
*/
class sfCsvReader
{
private
$header;
private
$file,
$path,
$initialized;
private
$length,
$delimiter,
$enclosure,
$to,
$from;
/**
* #param string $path Path to the file to read
* #param char $delimiter Character delimiting fields (Optional)
* #param char $enclosure Character enclosing fields (Optional)
* #param integer $length PHP's fgetcsv length parameter (Optional)
*/
function __construct($path, $delimiter = ',', $enclosure = '"', $length = null)
{
$this->path = $path;
$this->length = $length;
$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
$this->header = array(
'map' => null,
'selected' => array()
);
$this->initialized = false;
}
public function close()
{
if ($this->file !== null)
{
fclose($this->file);
$this->file = null;
$this->initialized = false;
}
}
public function open($path = null)
{
$this->close();
if ($path !== null)
{
$this->path = $path;
}
if (!($this->file = fopen($this->path, "r")))
{
throw new Exception("File can not be opened (".$this->path.").");
}
$this->initialized = true;
$this->map();
}
public function setSelectColumns($selected = array())
{
$this->test = true;
if (!is_array($selected))
{
$selected = explode(',', preg_replace('/\s+/', '', $selected));
}
$this->header['selected'] = $selected;
$this->map();
}
public function clearSelectColumns()
{
$this->header['selected'] = array();
$this->map();
}
private function map()
{
if ($this->initialized)
{
$this->all = false;
$x = count($this->header['selected']); // N. of selected columns
$y = 0; // N. of real columns
$z = 0; // N. of matching columns
if ($x == 0)
{ // No selection. All fields.
$this->header['map'] = null;
}
else
{
$this->header['map'] = array();
fseek($this->file, 0, SEEK_SET);
if ($line = fgetcsv($this->file, $this->length, $this->delimiter, $this->enclosure))
{
$y = count($line);
if ($y > 0)
{
$common = array_intersect($line, $this->header['selected']);
$z = count($common);
if (($y < $x) || (($x > $z) && ($z > 0)))
{ // More columns in selection than in file or less common columns than selection
throw new Exception("Too much columns or non existing columns in selection (LINE: $y, SEL: $x, COMMON: $z).");
}
if ($z == 0)
{ // Relaxed Mapping: 0 matches found, numerical.
foreach ($this->header['selected'] as $i => $name)
{
$this->header['map'][$name] = $i;
}
fseek($this->file, 0, SEEK_SET);
}
else if ($z == $x)
{ // Absolute Mapping: First line is header.
foreach ($line as $i => $name)
{
$this->header['map'][$name] = $i;
}
}
} // Has columns
} // Read line
} // N columns selected
} // Initialized
}
public function read()
{
if (!$this->initialized)
{
throw new Exception('sfCsvReader is not ready.');
}
if ($line = fgetcsv($this->file, $this->length, $this->delimiter, $this->enclosure))
{
if (is_array($this->header['map']))
{
$res = array();
foreach ($this->header['selected'] as $name)
{
if ($this->to !== null)
{
$res[$name] = $this->encode($line[$this->header['map'][$name]], $this->to, $this->from);
}
else
{
$res[$name] = $line[$this->header['map'][$name]];
}
}
return $res;
}
else
{
return $line;
}
}
else
{
return null;
}
}
private function encode($str, $to, $from = null)
{
if ($from === null)
{
$from = mb_detect_encoding($str);
}
if (function_exists('iconv'))
{
return iconv($from, $to, $str);
}
else
{
return mb_convert_encoding($str, $to, $from);
}
}
public function setCharset($to, $from = null)
{
$this->to = $to;
$this->from = $from;
}
function __destruct()
{
$this->close();
}
}
Are you loading the script before call them?
Try to add the following code to app/autoload.php inside the $loader->registerNamespaces(array(... array declaration:
'SfCsvReader' => __DIR__.'/../src/Acme/StoreBundle/Entity/sfCsvReader.php',
After that, rename the namespace inside the sfCsvReader.php file to namespace SfCsvReader\sfCsvReader; and replace the namespace requesting in your controller to use SfCsvReader\sfCsvReader;.
This should work fine, but maybe you should move your file to a more proper directory, for example in the vendor/sfCsvReader directory of the project.
You can follow the recommendations in the Symfony 2.0 documentation.
The autoloading info are in the following link The ClassLoader Component.
More info about namespaces can be found in php.net.