How to make a little function that given a directory it returns the number of lines (counts \r\n) of .php files between <?php and ?>?
Usage:
echo countsLineOfCode('D:/dir/code/');
// returns 323;
function countLinesOfCode($path) {
$lines = 0;
$items = glob(rtrim($path, '/') . '/*');
foreach($items as $item) {
if (is_file($item) AND pathinfo($item, PATHINFO_EXTENSION) == 'php') {
$fileContents = file_get_contents($item);
preg_match_all('/<\?(?:php)?(.*?)($|\?>)/s', $fileContents, $matches);
foreach($matches[1] as $match) {
$lines += substr_count($match, PHP_EOL);
}
} else if (is_dir($item)) {
$lines += countLinesOfCode($item);
continue;
}
}
return $lines;
}
var_dump(countLinesOfCode(dirname(__FILE__))); // int(31) (works for me)
Keep in mine this is counting newlines, not end of line character ;. For example, the line below will be considered one line...
var_dump($files); echo 'something'; exit;
It also counts lines without any PHP code, e.g. the below code will be 4 lines...
<?php
$a = 3;
It also doesn't count the <?php or closing (if present).
Let me know if it (a) shouldn't match empty lines, (b) should match semi colons instead (will need to ensure they are not appearing within a string) and/or (c) it should match the opening and closing tag (will be easy as changing $matches[1] in the foreach to $matches[0]).
PHPLOC
A tool for quickly measuring the size and analyzing the structure of a PHP project.
recursive version of alex function
function countLinesOfCode($path) {
$lines = 0;
$files = glob(rtrim($path, '/') . '/*');
foreach($files as $file) {
if (is_dir($file)){
if ($file=='.' || $file=='..')
continue;
$lines+=countLinesOfCode($file);
} else if (substr($file,-4)!='.php')
continue;
echo 'Counting on ' . $file .'<br>';
$fileContents = file_get_contents($file);
preg_match_all('/<\?(?:php)?(.*?)(?:$|\?>)/s', $fileContents, $matches);
foreach($matches[1] as $match) {
$lines += substr_count($match, PHP_EOL);
}
}
return $lines;
}
I made it work based on this Answer and the documentation for RecursiveDirectoryIterator.
$path = realpath( '/path/to/directory' );
$lines = $files = 0;
$objects = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $path ),
RecursiveIteratorIterator::SELF_FIRST
);
foreach( $objects as $name => $fileinfo )
{
if ( !$fileinfo->isFile() )
continue;
if( false === strpos( $name,'.php' ) )
continue;
$files++;
$read = $fileinfo->openFile();
$read->setFlags( SplFileObject::READ_AHEAD );
$lines += iterator_count( $read ) - 1; // -1 gives the same number as "wc -l"
}
printf( "Found %d lines in %d files.", $lines, $files );
Related
Solved on 2 steps:
Get the lines: https://stackoverflow.com/a/51350572/8524395
Remove the lines after getting them: https://stackoverflow.com/a/51377052/8524395
I have a large file, I want to take 1000 lines from the end of this file, then remove them.
I am currently using this:
function deleteLineInFile($file,$string)
{
$i=0;
$array=array();
$read = fopen($file, "r") or die("can't open the file");
while(!feof($read)) {
$array[$i] = fgets($read);
++$i;
}
fclose($read);
$write = fopen($file, "w") or die("can't open the file");
foreach($array as $a) {
if(!strstr($a,$string)) fwrite($write,$a);
}
fclose($write);
}
$goods = '';
$file = file("../products/".$PidFileName);
for ($i = max(0, count($file)-1001); $i < count($file); $i++) {
$goods = $goods.$file[$i] . '<br />';
deleteLineInFile("../products/".$PidFileName, $file[$i]);
}
I want to save the lines which I got in $goods
However, it times out because of the file size.
If you want to get N lines from EOF, you can use SPLFileObject (added in PHP 5.1):
$num_to_cut = 1000; // must be an integer and not a string
$new_file = new SplFileObject("limited_test.txt", "w");
$old_file = new SplFileObject('test.txt');
// here we get count of lines: go to EOF and get line number
$old_file->seek($old_file->getSize());
$linesTotal = $old_file->key()+1;
// and write data to new file
foreach( new LimitIterator($old_file, $linesTotal-$num_to_cut) as $line) {
$new_file->fwrite($line);
}
To remove the lines after getting them from a LARGE file:
The best way to do that is to use sed | But if you don't have access to use the exec() function then this is a function that you can use.
function replace_file($path, $string, $replace)
{
set_time_limit(0);
if (is_file($path) === true)
{
$file = fopen($path, 'r');
$temp = tempnam('./', 'tmp');
if (is_resource($file) === true)
{
while (feof($file) === false)
{
file_put_contents($temp, str_replace($string, $replace, fgets($file)), FILE_APPEND);
}
fclose($file);
}
unlink($path);
}
return rename($temp, $path);
}
Source of the function: https://stackoverflow.com/a/2159135/8524395
To remove the line use it like that:
replace_file('myfile.txt', 'RemoveThisPlease', '');
If you used MrSmile's answer to get the lines, then replace "RemoveThisPlease" with $line
I have a txt file that I want to read backwards, currently I'm using this:
$fh = fopen('myfile.txt','r');
while ($line = fgets($fh)) {
echo $line."<br />";
}
This outputs all the lines in my file.
I want to read the lines from bottom to top.
Is there a way to do it?
First way:
$file = file("test.txt");
$file = array_reverse($file);
foreach($file as $f){
echo $f."<br />";
}
Second Way (a):
To completely reverse a file:
$fl = fopen("\some_file.txt", "r");
for($x_pos = 0, $output = ''; fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
$output .= fgetc($fl);
}
fclose($fl);
print_r($output);
Second Way (b):
Of course, you wanted line-by-line reversal...
$fl = fopen("\some_file.txt", "r");
for($x_pos = 0, $ln = 0, $output = array(); fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
$char = fgetc($fl);
if ($char === "\n") {
// analyse completed line $output[$ln] if need be
$ln++;
continue;
}
$output[$ln] = $char . ((array_key_exists($ln, $output)) ? $output[$ln] : '');
}
fclose($fl);
print_r($output);
Try something simpler like this..
print_r(array_reverse(file('myfile.txt')));
Here is my solution for just printing the file backwards. It is quite memory-friendly. And seems more readable (IMO [=in my opinion]).
It goes through the file backwards, count the characters till start of a line or start of the file and then reads and prints that amount of characters as a line, then moves cursor back and reads another line like that...
if( $v = #fopen("PATH_TO_YOUR_FILE", 'r') ){ //open the file
fseek($v, 0, SEEK_END); //move cursor to the end of the file
/* help functions: */
//moves cursor one step back if can - returns true, if can't - returns false
function moveOneStepBack( &$f ){
if( ftell($f) > 0 ){ fseek($f, -1, SEEK_CUR); return true; }
else return false;
}
//reads $length chars but moves cursor back where it was before reading
function readNotSeek( &$f, $length ){
$r = fread($f, $length);
fseek($f, -$length, SEEK_CUR);
return $r;
}
/* THE READING+PRINTING ITSELF: */
while( ftell($v) > 0 ){ //while there is at least 1 character to read
$newLine = false;
$charCounter = 0;
//line counting
while( !$newLine && moveOneStepBack( $v ) ){ //not start of a line / the file
if( readNotSeek($v, 1) == "\n" ) $newLine = true;
$charCounter++;
}
//line reading / printing
if( $charCounter>1 ){ //if there was anything on the line
if( !$newLine ) echo "\n"; //prints missing "\n" before last *printed* line
echo readNotSeek( $v, $charCounter ); //prints current line
}
}
fclose( $v ); //close the file, because we are well-behaved
}
Of course replace PATH_TO_YOUR_FILE with your own path to your file, # is used when opening the file, because when the file is not found or can't be opened - warning is raised - if you want to display this warning - just remove the error surpressor '#'.
If the file is not so big you can use file():
$lines = file($file);
for($i = count($lines) -1; $i >= 0; $i--){
echo $lines[$i] . '<br/>';
}
However, this requires the whole file to be in memory, that's why it is not suited for really large files.
Here's my simple solution without messing up anything or adding more complex code
$fh = fopen('myfile.txt','r');
while ($line = fgets($fh)) {
$result = $line . "<br>" . $result;
}
echo $result // or return $result if you are using it as a function
How to count specific lines in a text file depending on a particular variable in that line.
For example i need to count the lines of a text file only containing for instance $item1 or $item2 etc.
Sounds like you need something like what grep -c do in the shell, try something like this:
$item1 = 'match me';
$item2 = 'match me too';
// Thanks to #Baba for the suggestion:
$match_count = count(
preg_grep(
'/'.preg_quote($item1).'|'.preg_quote($item2).'/i',
file('somefile_input.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
)
);
// does the same without creating a second array with the matches
$match_count = array_reduce(
file('somefile_input.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES),
function($match_count, $line) use ($item1, $item2) {
return
preg_match('/'.preg_quote($item1).'|'.preg_quote($item2).'/i', $line) ?
$match_count + 1 : $match_count;
}
);
The above code sample uses the file() function to read the file into an array (splitted by lines), array_reduce() to iterate that array and preg_match() inside the iteration to see if a line matched (the /i at the end makes it case-insensitive).
You could use a foreach as well too.
This code reads file.php and counts only lines containing '$item1' or '$item2'. The check itself could be finetuned, since you have to add a new stristr() for every word you want to check.
<?php
$file = 'file.php';
$fp = fopen($file, 'r');
$size = filesize($file);
$content = fread($fp, $size);
$lines = preg_split('/\n/', $content);
$count = 0;
foreach($lines as $line) {
if(stristr($line, '$item1') || stristr($line, '$item2')) {
$count++;
}
}
echo $count;
Read your file line by line and use strpos to determine if a line contains a specific string/item.
$handle = fopen ("filename", "r");
$counter = 0;
while (!feof($handle))
{
$line = fgets($handle);
// or $item2, $item3, etc.
$pos = strpos($line, $item);
if ($pos !== false)
{
$counter++
}
}
fclose ($handle);
I'm working on a slightly new project. I wanted to know how many files are in a certain directory.
<div id="header">
<?php
$dir = opendir('uploads/'); # This is the directory it will count from
$i = 0; # Integer starts at 0 before counting
# While false is not equal to the filedirectory
while (false !== ($file = readdir($dir))) {
if (!in_array($file, array('.', '..') and !is_dir($file)) $i++;
}
echo "There were $i files"; # Prints out how many were in the directory
?>
</div>
This is what I have so far (from searching). However, it is not appearing properly? I have added a few notes so feel free to remove them, they are just so I can understand it as best as I can.
If you require some more information or feel as if I haven't described this enough please feel free to state so.
You can simply do the following :
$fi = new FilesystemIterator(__DIR__, FilesystemIterator::SKIP_DOTS);
printf("There were %d Files", iterator_count($fi));
You can get the filecount like so:
$directory = "/path/to/dir/";
$filecount = count(glob($directory . "*"));
echo "There were $filecount files";
where the "*" is you can change that to a specific filetype if you want like "*.jpg" or you could do multiple filetypes like this:
glob($directory . "*.{jpg,png,gif}",GLOB_BRACE)
the GLOB_BRACE flag expands {a,b,c} to match 'a', 'b', or 'c'
Note that glob() skips Linux hidden files, or all files whose names are starting from a dot, i.e. .htaccess.
Try this.
// Directory
$directory = "/dir";
// Returns an array of files
$files = scandir($directory);
// Count the number of files and store them inside the variable..
// Removing 2 because we do not count '.' and '..'.
$num_files = count($files)-2;
You should have :
<div id="header">
<?php
// integer starts at 0 before counting
$i = 0;
$dir = 'uploads/';
if ($handle = opendir($dir)) {
while (($file = readdir($handle)) !== false){
if (!in_array($file, array('.', '..')) && !is_dir($dir.$file))
$i++;
}
}
// prints out how many were in the directory
echo "There were $i files";
?>
</div>
The best answer in my opinion:
$num = count(glob("/exact/path/to/files/" . "*"));
echo $num;
It doesnt counts . and ..
Its a one liner
Im proud of it
Since I needed this too, I was curious as to which alternative was the fastest.
I found that -- if all you want is a file count -- Baba's solution is a lot faster than the others. I was quite surprised.
Try it out for yourself:
<?php
define('MYDIR', '...');
foreach (array(1, 2, 3) as $i)
{
$t = microtime(true);
$count = run($i);
echo "$i: $count (".(microtime(true) - $t)." s)\n";
}
function run ($n)
{
$func = "countFiles$n";
$x = 0;
for ($f = 0; $f < 5000; $f++)
$x = $func();
return $x;
}
function countFiles1 ()
{
$dir = opendir(MYDIR);
$c = 0;
while (($file = readdir($dir)) !== false)
if (!in_array($file, array('.', '..')))
$c++;
closedir($dir);
return $c;
}
function countFiles2 ()
{
chdir(MYDIR);
return count(glob("*"));
}
function countFiles3 () // Fastest method
{
$f = new FilesystemIterator(MYDIR, FilesystemIterator::SKIP_DOTS);
return iterator_count($f);
}
?>
Test run: (obviously, glob() doesn't count dot-files)
1: 99 (0.4815571308136 s)
2: 98 (0.96104407310486 s)
3: 99 (0.26513481140137 s)
Working Demo
<?php
$directory = "../images/team/harry/"; // dir location
if (glob($directory . "*.*") != false)
{
$filecount = count(glob($directory . "*.*"));
echo $filecount;
}
else
{
echo 0;
}
?>
I use this:
count(glob("yourdir/*",GLOB_BRACE))
<?php echo(count(array_slice(scandir($directory),2))); ?>
array_slice works similary like substr function, only it works with arrays.
For example, this would chop out first two array keys from array:
$key_zero_one = array_slice($someArray, 0, 2);
And if You ommit the first parameter, like in first example, array will not contain first two key/value pairs *('.' and '..').
Based on the accepted answer, here is a way to count all files in a directory RECURSIVELY:
iterator_count(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator('/your/directory/here/', \FilesystemIterator::SKIP_DOTS)
)
)
$it = new filesystemiterator(dirname("Enter directory here"));
printf("There were %d Files", iterator_count($it));
echo("<br/>");
foreach ($it as $fileinfo) {
echo $fileinfo->getFilename() . "<br/>\n";
}
This should work
enter the directory in dirname. and let the magic happen.
Maybe usefull to someone. On a Windows system, you can let Windows do the job by calling the dir-command. I use an absolute path, like E:/mydir/mysubdir.
<?php
$mydir='E:/mydir/mysubdir';
$dir=str_replace('/','\\',$mydir);
$total = exec('dir '.$dir.' /b/a-d | find /v /c "::"');
$files = glob('uploads/*');
$count = 0;
$totalCount = 0;
$subFileCount = 0;
foreach ($files as $file)
{
global $count, $totalCount;
if(is_dir($file))
{
$totalCount += getFileCount($file);
}
if(is_file($file))
{
$count++;
}
}
function getFileCount($dir)
{
global $subFileCount;
if(is_dir($dir))
{
$subfiles = glob($dir.'/*');
if(count($subfiles))
{
foreach ($subfiles as $file)
{
getFileCount($file);
}
}
}
if(is_file($dir))
{
$subFileCount++;
}
return $subFileCount;
}
$totalFilesCount = $count + $totalCount;
echo 'Total Files Count ' . $totalFilesCount;
Here's a PHP Linux function that's considerably fast. A bit dirty, but it gets the job done!
$dir - path to directory
$type - f, d or false (by default)
f - returns only files count
d - returns only folders count
false - returns total files and folders count
function folderfiles($dir, $type=false) {
$f = escapeshellarg($dir);
if($type == 'f') {
$io = popen ( '/usr/bin/find ' . $f . ' -type f | wc -l', 'r' );
} elseif($type == 'd') {
$io = popen ( '/usr/bin/find ' . $f . ' -type d | wc -l', 'r' );
} else {
$io = popen ( '/usr/bin/find ' . $f . ' | wc -l', 'r' );
}
$size = fgets ( $io, 4096);
pclose ( $io );
return $size;
}
You can tweak to fit your needs.
Please note that this will not work on Windows.
simple code add for file .php then your folder which number of file to count its
$directory = "images/icons";
$files = scandir($directory);
for($i = 0 ; $i < count($files) ; $i++){
if($files[$i] !='.' && $files[$i] !='..')
{ echo $files[$i]; echo "<br>";
$file_new[] = $files[$i];
}
}
echo $num_files = count($file_new);
simple add its done ....
I have a file file.txt. This file has portions and parts that recur throughout the file. I
am trying to read the parts between the last and the first key words.
I have managed to get the first and the last key words but I can't read the lines between the key words.
Here is my script
$file=file('file.txt');
$begin = 'first_line';
$end='last_line';
foreach ($file as $lineNumber => $line) {
$lineNumber++;
if (strpos($line,$begin))
{
echo $lineNumber.$line."<br/>";
}
elseif (strpos($line,$end))
{
echo $value."<br/>";
}
echo $lineNumber. $line."<br/>";
}
Please some one assist me.
Here you go:
$lines=file('data.txt');
$begin = 'first_line';
$end='last_line';
$switch = false;
$content = "";
foreach ($lines as $line_num => $line) {
if(strpos($line, $begin) !== false) {$switch = true;continue;}
if(strpos($line, $end) !== false) $switch = false;
if(!$switch) continue;
$content .= "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br />\n";
}
echo $content;
This will do it:
$file = file('file.txt');
$begin = 'first_line';
$end = 'last_line';
$isInside = false;
foreach ($file as $lineNumber => $line)
{
$lineNumber++;
if (!(strpos($line,$begin)===false))
$isInside = true;
if ($isInside)
echo $lineNumber." : ".$line."<br/>";
if (!(strpos($line,$end)===false))
$isInside = false;
}
Some points:
You were displaying everything regardless, my script only shows lines between $begin and $end.
Your comparison is case-sensitive
You had a major bug using strpos and assuming it returns true if it matches. It could also return 0 if the string matches at the beginning,hence using === to catch this. See the disclaimer on the strpos page.
$file=fopen("welcome.txt","r");
while(!feof($file))
{
$open=fgets($file);
print $open;
}
fclose($file);