PHP - Problem skipping 0D0A lines from text file - php

I get a text file (.sql) which contains MySQL inserts. I found that there are times when blank lines are included. These blank lines contain hex value 0D0A (Windows newline). MySQL reports an error when a blank line is sent for the query. So, as I read/send the lines to MySQL I want to skip sending any blank lines. I came up with the following code, but it's not working as I expected. Newlines are removed but blank lines are still sent to MySQL. I traced the problem to the PHP command empty(). According to the docs " " should be considered empty. So why does it not skip blank lines? I've spent a few days working on this but nothing I try works. I need another set of eyes, please. Here is the code:
<?php
$bom = pack("H*", "EFBBBF");
if(($reading = fopen("sample.sql", "r")) !== false)
{
$sql = preg_replace("/^$bom/", "", fgets($reading));
while(!feof($reading))
{
$sql = str_replace(array("\n", "\r", "\r\n"), " ", $sql);
if(!empty($sql))
{
echo("{$sql}<br>");
$sql = fgets($reading);
}
}
if(!feof($reading))
{
echo("Unexpected read error in file." . PHP_EOL);
}
fclose($reading);
}
?>
I replace the newlines with a space (if I try to remove the newlines using "" IIS will crash). I expect the empty command to skip the space but it doesn't. The sample data you need to run this script is here.
Thanks for any and all help,
Charles

After some much needed sleep I found my problem (sort of). I still think empty() should see " " as empty, I'll check the docs again.
To fix my code I had to change the str_replace to remove the newlines completely. Then I had to move fgets out of the if statement (if the line is blank you still need to get the next line).
In case anyone else comes across this problem here is the corrected code:
<?php
$bom = pack("H*", "EFBBBF");
if(($reading = fopen("sample.sql", "r")) !== false)
{
$sql = preg_replace("/^$bom/", "", fgets($reading));
while(!feof($reading))
{
$sql = str_replace(array("\r\n", "\n", "\r"), "", $sql);
if(!empty($sql))
{
echo("{$sql}<br>");
}
$sql = fgets($reading);
}
if(!feof($reading))
{
echo("Unexpected read error in file." . PHP_EOL);
}
fclose($reading);
}
?>
Thanks for looking.

Related

How to replace PHP code in a file having newlinse

I got some files to change by clicking a button. To go for it, i have the old string to replace, saved in database, and also the new one.
On the click button, it executes a function that is gonna find the old string in the PHP file, then gonna replace it by the new one. (Final goal is to automate the PHP edits in a web software after an update).
My problem is that it perfectly works on short strings (without newline), but as soon as there is a newline into the file, nothing happens.
This is my actual code :
$path = '/mypath/' . $item['path'];
$old_code = $item['old_code'];
$new_code = $item['new_code'];
}
$pos = strpos(file_get_contents($path), $old_code);
$file = file_get_contents($path);
$str = str_replace($old_code, $new_code, $file);
file_put_contents($path, $str);
$pos is "true" if my $old_code doesn't have any newline.
I tried to use preg_match to remove \n, but the problem is that when i'll have to push my edits on the file with file_put_contents, every newline will also disapear.
Example of non-working str_replace :
echo "ok"; echo 'hey there is some spaces before'
echo 'this is a sentence';
$menu = ['test1', 'test200'];
print_r($menu);
$url = "/link/to/test";
$div = "echo \"<div class='central_container' align='center'>\";";
Do you have any idea for resolving this ?
Thanks
if I`m not wrong str_replace() work only with single lines . Its have 2 options.
Option line replace str_replace() with preg_replace() or just use https://regex101.com/ there also have code generator after you finish you Regex

How do I properly log only files changed with PHP shell_exec?

I have created a script which copies changed files from a development site to a live site that works flawlessly.
I'm now trying to log which files were changed and then add that list to a DB table that keeps track of changes.
I use shell_exec to run rsync for the copy and then am trying to trim the output and add \n for formatting.
The output is something like "sending incremental file list portalMaint.php sent 27,659 bytes received 81 bytes 55,480.00 bytes/sec total size is 101,582,367 speedup is 3,661.95".
Here is the code I have:
$command = "sudo -S rsync -av ".$exclude." ".$source." ".$dest." --delete 2>&1";
// --- Issue command and check for errors.
$exErrors = shell_exec($command);
if (stripos($exErrors, "error:") !== false || stripos($exErrors, "[sudo]")) {
$error = "Uh-OH, we have a problem! Don't Panic!";
$errors = $exErrors;
include("head.php");
include("template_".$currentPage.".html");
include("foot.php");
exit();
}else{
$filesCopied = $exErrors;
$filesCopied = substr($filesCopied, 0, strrpos($filesCopied, " sent "));
$filesCopied = preg_replace("/\s+/", "\n", $filesCopied);
}
This does NOT work. $filesCopied ends up being blank.
If I comment out $filesCopied = substr($filesCopied, 0, strrpos($filesCopied, " sent ")); I get the entire output unformatted.
What am I doing wrong? I just need the files that were changed 1 per line.
Thanks.
If your unformatted output have same pattern:
sending incremental file list file1.php sent ...
sending incremental file list file2.php sent ...
sending incremental file list file3.php sent ...
you can use preg_match_all() to capture the file names into array:
if (preg_match_all('/file list (.*?) sent /', $result, $matches)) {
$filesCopied = $matches[1];
} else {
echo 'Pattern does not match';
}
Found the answer!
As it turns out although the shell output was echoing as one line it was masking line breaks. So when it came to formatting the output the regex wasn't matching.
What I did was send the shell output to a file where I could see that it was line breaking.
So I took the shell output variable $filesCopied and ran it through preg_replace() using \R as the pattern. I found that here: Replace multiple newlines, tabs, and spaces
Thank you #Anggara as your code was better than mine for formatting and is what I am using.
Here is my final code:
$command = "sudo -S rsync -av ".$exclude." ".$source." ".$dest." --delete 2>&1";
// --- Issue command and check for errors.
$exErrors = shell_exec($command);
if (stripos($exErrors, "error:") !== false || stripos($exErrors, "[sudo]")) {
$error = "Uh-OH, we have a problem! Don't Panic!";
$errors = $exErrors;
include("head.php");
include("template_".$currentPage.".html");
include("foot.php");
exit();
}else{
// -- Strip invisible line breaks
$filesCopiedRaw = preg_replace('#\R+#', ' ', $exErrors);
// -- Strip all but files and folders from string and build an array
preg_match_all('/file list (.*?) sent /', $filesCopiedRaw, $matches);
$result = $matches[1];
// -- Convert array to single string
$filesCopied = "";
foreach($result as $file) {
$filesCopied .= $file." ";
}
// -- Replace spaces in string with line breaks
$filesCopied = preg_replace("/\s+/", "\n", $filesCopied);
}

CLI PHP Script - Show escaped/formatting characters

So this question applies for lots of languages, so don't be thrown off by the fact I'm using PHP in the terminal. An answer for say Python or Perl would probably also give what I need to know.
So I'm reading a text file, and I want to know what special characters are contained on every line. So for example, if the text file is this:
hello
world
I want the script to output "hello\nworld". My root problem is that I'm trying to write a PHP script which involves reading from a text file but I want it to ignore the blank lines but no matter what I try it still reads in the blank lines. I think it's because I'm not putting in the right match for the line so I'm trying to figure out how a blank line exists and I'm unsure if it's "\n" or "\t\t" etc.
Just do ordinary str_replace() like this:
$text = str_replace( array("\n","\r"), array('\n', '\r'), $text);
My solution, certainly more tedious, will remove blank lines, CLI PHP Script requires Shebang at the head:
#!/usr/bin/php
<?php
//
// main test:
//
$xarr = file("MyFilename.txt");
$n = count($xarr);
$strret = "";
for($i = 0; $i < $n; $i++)
{
//
// ignore blank lines:
//
if(! preg_match("/^$/", $xarr[$i]))
{
if($i > 0)
{
$strret .= "\\n";
}
$strret .= rtrim($xarr[$i]);
}
}
//
echo $strret . "\n";
?>
With a text file:
# cat MyFilename.txt
hello
world
It puts:
hello\nworld
I'll assume that by "special character", you mean only \n, \t, and \r.
Text file:
hello
world
foo
bar!
baz_
PHP:
$fp = fopen('textfile.txt', 'r');
while (!feof($fp)) {
$c = fgetc($fp);
if ($c == "\n") $c = '\n';
else if ($c == "\t") $c = '\t';
else if ($c == "\r") $c = '\r';
echo $c;
}
What the script above will basically do, is read each character of the file, and replace any occurrences of \t, \r, or \n that it finds. This eliminates the necessity to check for double-ups of characters.

PHP substr doesn't echo anything

I'm having problems with this code, and the PHP method 'substr' is playing up. I just don't get it. Here's a quick introduction what I'm trying to achieve. I have this massive XML-document with email-subscribers from Joomla. I'm trying to import it to Mailchimp, but Mailchimp have some rules for the syntax of the ways to import emails to a list. So at the moment the syntax is like this:
<subscriber>
<subscriber_id>615</subscriber_id>
<name><![CDATA[NAME OF SUBSCRIBER]]></name>
<email>THE_EMAIL#SOMETHING.COM</email>
<confirmed>1</confirmed>
<subscribe_date>THE DATE</subscribe_date>
</subscriber>
I want to make a simple PHP-script that takes all those emails and outputs them like this:
[THE_EMAIL#SOMETHING.COM] [NAME OF SUBSCRIBER]
[THE_EMAIL#SOMETHING.COM] [NAME OF SUBSCRIBER]
[THE_EMAIL#SOMETHING.COM] [NAME OF SUBSCRIBER]
[THE_EMAIL#SOMETHING.COM] [NAME OF SUBSCRIBER]
If I can do that, then I can just copy paste it into Mailchimp.
Now here's my PHP-script, so far:
$fileName = file_get_contents('emails.txt');
foreach(preg_split("/((\r?\n)|(\r\n?))/", $fileName) as $line){
if(strpos($line, '<name><![CDATA[')){
$name = strpos($line, '<name><![CDATA[');
$nameEnd = strpos($line, ']]></name>', $name);
$nameLength = $nameEnd-$name;
echo "<br />";
echo " " . strlen(substr($line, $name, $nameLength));
echo " " . gettype(substr($line, $name, $nameLength));
echo " " . substr($line, $name, $nameLength);
}
if(strpos($line, '<email>')){
$var1 = strpos($line, '<email>');
$var2 = strpos($line, '</email>', $var1);
$length = $var2-$var1;
echo substr($line, $var1, $length);
}
}
The first if-statement works as it should. It identifies, if there's an ''-tag on the line, and if there is, then it finds the end-tag and outputs the email with the substr-method.
The second if-statement is annoying me. If should do the same thing as the first if-statement, but it doesn't. The length is the correct length (I've checked). The type is the correct type (I've checked). But when I try to echo it, then nothing happens. The script still runs, but it doesn't write anything.
I've played around with it quite a lot and seem to have tried everything - but I can't figure it out.
Warning
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
You should be using if(strpos($line,'...') !== false) {
That aside, your file seems to be XML, so you should use an XML parser lest you fall under the pony he comes.
DOMDocument is a good one. You could do something like this:
$dom = new DOMDocument();
$dom->load("emails.txt");
$subs = $dom->getElementsByTagName('subscriber');
$count = $subs->length;
for( $i=0; $i<$l; $i++) {
$sub = $subs->item($i);
echo $sub->getElementsByTagName('email')->item(0)->nodeValue;
echo " ";
echo $sub->getElementsByTagName('name')->item(0)->nodeValue;
echo "\n";
}
This will output the names and emails in the format you described.
So there's a few things wrong with this, including the strpos command which will actually return 0 if it finds the tag at the beginning of the line, which doesn't appear to be what you intend.
Also, if the XML is not formatted exactly as you have, with each opening and closing tag on the one line, then your logic will fail as well.
It's not a good idea to re-invent XML processing for this reason...
Here as others have proposed, is a better solution to the problem*.
$xml = simplexml_load_file('emails.txt');
foreach( $xml->subscriber as $sub )
{
// Note that SimpleXML is aware of CDATA, and only outputs the text
$output = '[' . $sub->name . ']' . ' ' . '[' . $sub->email . ']';
}
*This assumes that you XML is valid, i.e. "subscriber" blocks are contained in a single parent at the top level. You can of course use simplexml documentation to adjust for your use case.

PHP: Opening .txt file, reading line by line, removing (YEAR)

I am looking for a suggestion on this:
I have a text file called movies.txt with about 900 lines, which contains one movie name per line. However, I would like to remove the year the movie has been released using PHP (which I am new to)
The format is basically:
A Nous la Liberte (1932)
About Schmidt (2002)
Absence of Malice (1981)
Adam's Rib (1949)
Adaptation (2002)
The Adjuster (1991)
The Adventures of Robin Hood (1938)
Affliction (1998)
The African Queen (1952)
So I am looking for a way to open the text file, reading it line by line and removing the (YEAR) values while also removing the space before the (YEAR).
Then I would like to save it as newmovies.txt
Would be great if you could show and explain me a solution that works for my needs. I am still very new to PHP (started a week ago) so it's all still magic to me.
You can read a file line-wise using the file() function. Then foreach over that and strip lines until the opening parenthesis.
For example
foreach (file($fn) as $line) {
$output[] = strtok($line, "(");
}
You may need to trim the extra space and add linebreaks again.
So a regex might be simpler and also asserts some structure without blindly cutting things off:
$text = file_get_contents($fn);
$text = preg_replace('/\s*\(\d+\)/m', '', $text);
# \s* is for spaces and \d+ is a placeholder for numbers
Then save that back.
<?php
$toWrite = "";
$handle = #fopen("input.txt", "r");
if ($handle) {
while (($buffer = fgets($handle, 4096)) !== false) {
$toWrite .= preg_replace('/\(\d+\)/', '', $buffer) . "\n";
}
if (!feof($handle)) {
echo "Error: unexpected fgets() fail\n";
}
fclose($handle);
file_put_contents("input.txt", $toWrite);
}
?>

Categories