Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
i have a file (in my case debug.log) and there is a lot of source code from many files in it. I want to extract these lines of code in seperate files.
Structure of my debug.log:
#NewFile#path/to/file.php
<?php
class ClassA {
function A() { do smth(); }
}
#NewFile#path/to/nextFile.php
<?php
class ClassA {
function A() { do smth(); }
}
#NewFile#path/to/thirdFile.php
...
Now i want to split by #NewFile# and want to save the Content in a new .php File.
This is my code for doing this:
$handle = fopen('debug.log', 'r');
$index = 1;
$filename = '/home/myuser/folder/file';
while (($line = fgets($handle)) !== false) {
if (strpos($line, '#NewFile#') !== false) {
$content = file_get_contents($filename . $index . '.php');
file_put_contents($filename . $index . '.php', $content . $line);
} else {
$index++;
}
}
fclose($handle);
Thanks for your help :)
Apart from the fact that a file called debug.log seems to contain PHP source (which, no matter how you look at it, is really weird), it's a fairly trivial thing to do:
The simplest way to reliably parse php files in php is to use the token_get_all function. In this case, it's a matter of doing something like this:
$tokens = token_get_all(file_get_contents('input_file.php'));
$file = null;
$contents = [];
foreach ($tokens as $token) {
//comment with #NewFile# in there?
if ($token[0] === T_COMMENT && strstr($token[1]{0}, '#NewFile#')) {
if ($file) {
//write code to file
file_put_contents($file, implode(PHP_EOL, $contents));
}
$contents = ['<?php '];
$file = str_replace('#NewFile#', '', $token[1]);//set file path
} else {
//use line numbers as key, append value of current token to the line
$contents[$token[2]] .= $token[1];
}
}
//write the last file
if ($file) {
file_put_contents($file, implode(PHP_EOL, $contents));
}
I'm iterating over all the parser tokens. If I encounter a T_COMMENT token containing the string #NewFile#, I take that as sign that I need to write my current buffer ($contents into the file that I last read from the previous comment. After that, I reassign $file to point to a new file (again, path and name taken from the comment), and start building the $contents buffer again.
After the loop, $file and $contents will contain all the tokens that should go in the last file, so I just do a quick check (make sure $file is set), and write whatever is in the buffer to that file.
Here is my own solution for my Problem, that solved it :)
$handle = fopen(dirname(__FILE__) . '/debug.log', 'r');
$fileName = '/file';
$dir = '/home/myuser/folder';
while (($line = fgets($handle)) !== false) {
if (strpos($line, '#NewFile#') === false) {
if (file_exists($dir . $fileName)) {
file_put_contents($dir . $fileName, $line, FILE_APPEND);
} else {
preg_match("/(\/.*\/)/", $fileName, $path);
if (!is_dir($dir . $path[0])) {
mkdir($dir . $path[0], 0777, true);
}
file_put_contents($dir . $fileName, $line);
}
} else {
$fileName = str_replace(".#NewFile#", '', $line);
$fileName = str_replace("#NewFile#", '', $fileName);
}
}
fclose($handle);
Related
This question already has answers here:
How to delete a line from the file with php?
(10 answers)
Closed last year.
i was wondering if it is posible to delete a single line in a txt file with php.
I am storing emailadresses in a flat txt file named databse-email.txt
I use this code for it:
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$email = $_POST['email-subscribe'] . ',' . "\n";
$store = file_put_contents('database-email.txt', $email, FILE_APPEND | LOCK_EX);
if($store === false) {
die('There was an error writing to this file');
}
else {
echo "$email successfully added!";
}
}
?>
Form:
<form action="" method="POST">
<input name="email-subscribe" type="text" />
<input type="submit" name="submit" value="Subscribe">
</form>
The content of the file looks like this:
janny#live.nl,
francis#live.nl,
harry#hotmail.com,
olga#live.nl,
annelore#mail.ru,
igor#gmx.de,
natasha#hotmail.com,
janny.verlinden#gmail.com,
All lines are , seperated
Lets say i want to delete only the emailadres: igor#gmx.de
How can i do that?
What i want to achieve is a unsubscribe form and delete a single line in the .txt file
You can use str_replace
$content = file_get_contents('database-email.txt');
$content = str_replace('igor#gmx.de,', '', $content);
file_put_contents('database-email.txt', $content);
Because of the way the filesystem works you can't do this in an intuitive way. You have to overwrite the file with all the lines except the one you want to delete, here's an example:
$emailToRemove = "igor#gmx.de";
$contents = file('database-email.txt'); //Read all lines
$contents = array_filter($contents, function ($email) use ($emailToRemove) {
return trim($email, " \n\r,") != $emailToRemove;
}); // Filter out the matching email
file_put_contents('database-email.txt', implode("\n", $contents)); // Write back
Here's a streaming alternative solution in the cases where the file does not fit in memory:
$emailToRemove = "igor#gmx.de";
$fh = fopen('database-email.txt', "r"); //Current file
$fout = fopen('database-email.txt.new', "w"); //New temporary file
while (($line = fgets($fh)) !== null) {
if (trim($line," \n\r,") != $emailToRemove) {
fwrite($fout, $line, strlen($line)); //Write to new file if needed
}
}
fclose($fh);
fclose($fout);
unlink('database-email.txt'); //Delete old file
rename('database-email.txt.new', 'database-email.txt'); //New file is old file
There is also a way to do this in-place to minimize extra disk needed but that is trickier.
You can do it programmatically which will just look over every line and if it not what you want to delete, it gets pushed to an array that will get written back to the file . Like below
$DELETE = "igor#gmx.de";
$data = file("database-email.txt");
$out = array();
foreach($data as $line) {
if(trim($line) != $DELETE) {
$out[] = $line;
}
}
$fp = fopen("database-email.txt", "w+");
flock($fp, LOCK_EX);
foreach($out as $line) {
fwrite($fp, $line);
}
flock($fp, LOCK_UN);
fclose($fp);
first read the file using fopen and fget , and make array to list the emails you want to remove , use in_array to check if value exists in array , and then after remove unwanted emails save the file using fwrite and you need to close the file after the read and the write operations using fclose
checkout this code
$data = "";
$emailsToRemove = ["igor#gmx.de" , "janny#live.nl"];
//open to read
$f = fopen('databse-email.txt','r');
while ($line = fgets($f)) {
$emailWithComma = $line . ",";
//check if email marked to remove
if(in_array($emailWithComma , $emailsToRemove))
continue;
$data = $data . $line;
}
fclose($f);
//open to write
$f = fopen('databse-email.txt','w');
fwrite($f, $data);
fclose($fh);
for delete special word and next delete blank line try this:
$file = "file_name.txt";
$search_for = "example_for_remove";
$file_data = file_get_contents($file);
$pattern = "/$search_for/mi";
$file_data_after_remove_word = preg_replace($pattern, '', $file_data);
$file_data_after_remove_blank_line = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $file_data_after_remove_word);
file_put_contents($file,$file_data_after_remove_blank_line);
Im trying to make a Php file that receives nothing and checks every file on the folder, searching for a string inside them. it echos a array of filenames that have the string inside. Any way to do it, possibly with low memory usage?
Thank you a lot.
To achieve something like this, I recommend you read about the DirectoryIterator class, file_get_contents, and about strings in PHP.
Here is an example of how you can read the contents of a a given directory ($dir) and use strstr to search for a specific string occurrence in each file's contents ($contents):
<?php
$dir = '.';
if (substr($dir, -1) !== '/') {
$dir .= '/';
}
$matchedFiles = [];
$dirIterator = new \DirectoryIterator($dir);
foreach ($dirIterator as $item) {
if ($item->isDot() || $item->isDir()) {
continue;
}
$file = realpath($dir . $item->getFilename());
// Skip this PHP file.
if ($file === __FILE__) {
continue;
}
$contents = file_get_contents($file);
// Seach $contents for what you're looking for.
if (strstr($contents, 'this is what I am looking for')) {
echo 'Found something in ' . $file . PHP_EOL;
$matchedFiles[] = $file;
}
}
var_dump($matchedFiles);
There is some extra code in this example (adding a trailing slash to $dir, skipping dot files and directories, skipping itself, etc.) that I encourage you to read and learn about.
<?php
$folderPath = '/htdocs/stock/tae';
$searchString = 'php';
$cmd = "grep -r '$searchString' $folderPath";
$output = array();
$files = array();
$res = exec($cmd, $output);
foreach ($output as $line) {
$files[] = substr($line, 0, strpos($line, ':'));
}
print_r($files);
I am taking data from text file( data is: daa1 daa2 daa3 on separate lines) then trying to make folders with exact name but only daa3 folders is created. Also when i use integer it creates all folders, same is the case with static string i.e "faraz".
$file = __DIR__."/dataFile.txt";
$f = fopen($file, "r");
$line =0;
while ( $line < 5 )
{
$a = fgets($f, 100);
$nl = mb_strtolower($line);
$nl = "checkmeck/".$nl;
$nl = $nl."faraz"; // it works for static value i.e for faraz
//$nl = $nl.$a; // i want this to be the name of folder
if (!file_exists($nl)) {
mkdir($nl, 0777, true);
}
$line++;
}
kindly help
use feof function its much better to get file content also line by line
Check this full code
$file = __DIR__."/dataFile.txt";
$linecount = 0;
$handle = fopen($file, "r");
$mainFolder = "checkmeck";
while(!feof($handle))
{
$line = fgets($handle);
$foldername = $mainFolder."/".trim($line);
//$line is line name daa1,daa2,daa3 etc
if (!file_exists($foldername)) {
mkdir($foldername, 0777, true);
}
$linecount++;
unset($line);
}
fclose($handle);
output folders
1countfaraz
2countfaraz
3countfaraz
Not sure why you're having trouble with your code, but I find it to be more straightforward to use file_get_contents() instead of fopen() and fgets():
$file = __DIR__."/dataFile.txt";
$contents = file_get_contents($file);
$lines = explode("\n", $contents);
foreach ($lines as $line) {
$nl = "checkmeck/". $line;
if (!file_exists($nl)) {
echo 'Creating file '. $nl . PHP_EOL;
mkdir($nl, 0777, true);
echo 'File '. $nl .' has been created'. PHP_EOL;
} else {
echo 'File '. $nl .' already exists'. PHP_EOL;
}
}
The echo statements above are for debugging so that you can see what your code is doing. Once it is working correctly, you can remove them.
So you get the entire file contents, split it (explode()) by the newline character (\n), and then loop through the lines in the file. If what you said is true, and the file looks like:
daa1
daa2
daa3
...then it should create the following folders:
checkmeck/daa1
checkmeck/daa2
checkmeck/daa3
I sense that I am almost there.
Here is a .txt file, which is about 60 Kbytes and full of German words. Every word is on a new line.
I want to iterate through it with this code:
<?php
$file = "GermanWords.txt";
$f = fopen($file,"r");
$parts = explode("\n", $f);
foreach ($parts as &$v)
{
echo $v;
}
?>
When I execute this code, I get: Resourceid#2
The word resource is not in the .txt, I do not know where it comes from.
How can I manage to show up all words in the txt?
No need for fopen just use file_get_contents:
$file = "GermanWords.txt";
$contents = file_get_contents($file);
$lines = explode("\n", $contents); // this is your array of words
foreach($lines as $word) {
echo $word;
}
fopen() just opens the file, it doesn't read it -- In your code, $f contains a file handle, not the file contents. This is where the word "Resource" comes from; it's PHP's internal name for the file handle.
One answer would be to replace fopen() with file_get_contents(). This opens and reads the file in one action. This would solve the problem, but if the file is big, you probably don't want to read the whole thing into memory in one go.
So I would suggest instead using SplFileObject(). The code would look like this:
<?php
$file = "GermanWords.txt";
$parts = new SplFileObject($file);
foreach ($parts as $line) {
echo $line;
}
?>
It only reads into memory one line at at time, so you don't have to worry about the size of the file.
Hope that helps.
See the PHP manual for more info: http://php.net/manual/en/splfileobject.construct.php
$f, the result of fopen is a resource, not the contents of the file. If you just want an array of the lines contained in the file, you can use file:
$parts = file('GermanWords.txt');
foreach($parts as $v){
echo $v;
}
Alternatively, if you want to stick with fopen you can use fread to read the content:
$f = fopen('GermanWords.txt', 'r');
// read the entire file into $contents
$contents = fread($f, filesize('GermanWords.txt'));
fclose($handle);
$parts = explode("\n", $contents);
The SplFileObject provides a way to do that :
$file = new SplFileObject("file.txt");
while (!$file->eof()) {
echo $file->fgets();
}
And if you prefer the foreach loop, you can create a generator function for that :
function lines($filename) {
$file = new SplFileObject($filename);
while (!$file->eof()) {
yield $file->fgets();
}
}
foreach (lines('German.txt') as $line) {
echo $line;
}
Reading the entire content of the file (with file_get_contents) before treating it can be memory consuming.
If you want to treat a file line by line, this class might help you.
It implements an Iterator (see phpdoc about it), that can be walked through in a foreach loop. Only the last line read is stored in memory.
class TxtFileIterator implements \Iterator{
protected $fileHandler;
protected $key;
protected $current;
protected $fileName;
function __construct($fileName){
$this->fileHandler = fopen($fileName, "r") or die("Unable to open file!");
$this->fileName = $fileName;
$this->key = 0;
}
function __destruct(){
fclose( $this->fileHandler );
}
//Iterator interface
public function current (){
return $this->current;
}
public function key (){
return $this->key;
}
public function next (){
if ( $this->valid() ){
$this->current = fgets( $this->fileHandler );
$this->key++;
}
}
public function rewind (){
$this->__destruct();
$this->__construct( $this->fileName );
}
public function valid (){
return !feof( $this->fileHandler );
}
Usage :
$iterator = new TxtFileIterator("German.txt");
foreach ($iterator as $line) {
echo $line;// or do whatever you want with line
}
I have an PHP app with houndreds of files. The problem is that one or several files apparently have a BOM in them, so including them causes error when creating the session... Is there a way how to reconfigure PHP or the server or how can I get rid of the BOM? Or at least identify the source? I would prefer a PHP solution if available
The real solution of course is to fix your editor settings (and the other team members as well) to not store files with UTF byte order mark. Read on here: https://stackoverflow.com/a/2558793/43959
You could use this function to "transparently" remove the BOM before including another PHP file.
Note: I really recommend you to fix your editor(s) / files instead of doing nasty things with eval() which i demonstrate here.
This is just a proof of concept:
bom_test.php:
<?php
function bom_safe_include($file) {
$fd = fopen($file, "r");
// read 3 bytes to detect BOM. file read pointer is now behind BOM
$possible_bom = fread($fd, 3);
// if the file has no BOM, reset pointer to beginning file (0)
if ($possible_bom !== "\xEF\xBB\xBF") {
fseek($fd, 0);
}
$content = stream_get_contents($fd);
fclose($fd);
// execute (partial) script (without BOM) using eval
eval ("?>$content");
// export global vars
$GLOBALS += get_defined_vars();
}
// include a file
bom_safe_include("test_include.php");
// test function and variable from include
test_function($test);
test_include.php, with BOM at beginning
test
<?php
$test = "Hello World!";
function test_function ($text) {
echo $text, PHP_EOL;
}
OUTPUT:
kaii#test$ php bom_test.php
test
Hello World!
I have been able to identify the files that carried BOM inside them with this script, maybe it helps someone else with the same problem in the future. Works without eval().
function fopen_utf8 ($filename) {
$file = #fopen($filename, "r");
$bom = fread($file, 3);
if ($bom != b"\xEF\xBB\xBF")
{
return false;
}
else
{
return true;
}
}
function file_array($path, $exclude = ".|..|libraries", $recursive = true) {
$path = rtrim($path, "/") . "/";
$folder_handle = opendir($path);
$exclude_array = explode("|", $exclude);
$result = array();
while(false !== ($filename = readdir($folder_handle))) {
if(!in_array(strtolower($filename), $exclude_array)) {
if(is_dir($path . $filename . "/")) {
// Need to include full "path" or it's an infinite loop
if($recursive) $result[] = file_array($path . $filename . "/", $exclude, true);
} else {
if ( fopen_utf8($path . $filename) )
{
//$result[] = $filename;
echo ($path . $filename . "<br>");
}
}
}
}
return $result;
}
$files = file_array(".");
vim $(find . -name \*.php)
once inside vim:
:argdo :set nobomb | :w