I wrote a script that uses file_get_contents() to open files on server, path is delivered by POST. I only had to receive path from POST and use str_replace() to change "%2F" to "/". Everything worked fine until today. Now in some of supported paths php makes unescaped hexadecimal codes that cannot be supplied to file_get_contents().
Example:
2 parameters:
end = wypisZgierz/Łagiewniki Nowe Zachód/koncowe.htm
start = wypisZgierz/Łagiewniki Nowe Zachód/ogolne.htm
source:
start=wypisZgierz%2F%C5%81agiewniki+Nowe+Zach%C3%B3d%2Fogolne.htm&end=wypisZgierz%2F%C5%81agiewniki+Nowe
+Zach%C3%B3d%2Fkoncowe.htm
Start works fine, but end not.
PHP error log:
PHP Warning: file_get_contents(wypisZgierz/\xc5\x81agiewniki Nowe Zach\xc3\xb3d/koncowe.htm): failed to open stream: No such file or directory
*EDIT 1 *
Thanks to rawurldecode() I coul skip my str_replace(), but this doesn't help with original problem.
Real php code:
<?php
session_start();
$start = "";
$end = "";
foreach ($_POST as $key => $value) {
if($key == "start") {
$start = $value;
$start = str_replace("%2F","/",$start);}
if($key == "end") {
$end = $value;
$end = str_replace("%2F","/",$end);
}
}
$tempstart = file_get_contents($start);
$html = $tempstart;
$tempend = file_get_contents($end);
$html = $html.$tempend;
echo $html;
?>
The problem is that for old data it works fine, and now once $start and $end doesn't work, once only $start works. And if i supply start and end with the same value it still shows error with end (with start it might work or not). #pcdoc
the php function rawurldecode should do the trick! But if you posted some real php code it'd be easier to determine your exact problem!
Related
I know I can use xpath, but in this case it wouldn't work because of the complexity of the navigation of the site.
I can only use the source code.
I have browsed all over the place and couldn't find a simple php solution that would:
Open the HTML source code page (I already have an exact source code page URL).
Select and extract the text between two codes. Not between a div. But I know the start and end variables.
So, basically, I need to extract the text between
knownhtmlcodestart> Text to extract <knownhtmlcodeend
What I'm trying to achieve in the end is this:
Go to a source code URL.
Extract the text between two codes.
Store the data temporarily (define the time manually for how long) on my web server in a simple text file.
Define the waiting time and then repeat the whole process again.
The website that I'm going to extract data from is changing dynamically. So it would always store new data into the same file.
Then I would use that data (but that's a question for another time).
I would appreciate it if anyone could lead me to a simple solution.
Not asking to write a code, but maybe someone did anything similar and sharing the code here would be helpful.
Thanks
I (shamefully) found the following function useful to extract stuff from HTML. Regexes sometimes are too complex to extract large stuff, e.g. a whole <table>
/*
$start - string marking the start of the sequence you want to extract
$end - string marking the end of it..
$offset - starting position in case you need to find multiple occurrences
returns the string between `$start` and `$end`, and the indexes of start and end
*/
function strExt($str, $start, $end = null, $offset = 0)
{
$p1 = mb_strpos($str,$start,$offset);
if ($p1 === false) return false;
$p1 += mb_strlen($start);
$p2 = $end === null ? mb_strlen($str) : mb_strpos($str,$end, $p1+1);
return
[
'str' => mb_substr($str, $p1, $p2-$p1),
'start' => $p1,
'end' => $p2];
}
This would assume the opening and closing tag are on the same line (as in your example). If the tags can be on separate lines, it wouldn't be difficult to adapt this.
$html = file_get_contents('website.com');
$lines = explode("\n", $html);
foreach($lines as $word) {
$t1 = strpos($word, "knownhtmlcodestart");
$t2 = strpos($word, "knownhtmlcodeend");
if ($t1)
$c1 = $t1;
if ($t2)
$c2 = $t2;
if ($c1 && $c2){
$text = substring($word, $c1, $c2-$c1);
break;
}
}
echo $text;
I have to write a function that return the sum of all the numbers in a file.
The text file is numbers.txt:
1
1
2
3
5
8
13
21
The code I write is:
function sumFromFileInput($fileName) {
$total = 0;
$file = fopen("numbers.txt", "r");
while ($number = fgets($file)) {
$total += $number;
}
fclose($file);
return $total;
}
The output should be 54 whereas my output is 124712203354.
Please help me to figure out what I did wrong.
You can use file() for this purpose and simplifiy your code:
$trimmed = file('<provide file path here>', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$sum = array_sum($trimmed);
echo $sum;
In case you added values as string into file then you need to convert them to Integer first.
Add below line before array_sum() line:
$trimmed = array_map('intval', $trimmed);
function sumFromFileInput($fileName) {
$total = 0;
$file = fopen("numbers.txt", "r");
while (!feof($file)) { #this will give you a true value until it reaches end of the numbers.txt last line
$total += (int) fgets($file); # this will read file lines one by one
}
fclose($file);
return $total;
}
What happens if you modify your code to be like this:
function sumFromFileInput($fileName) {
$total = 0;
$file = fopen("numbers.txt", "r");
while ($number = fgets($file)) {
// Making sure to add integer values here
$total += (int)$number;
}
fclose($file);
return $total;
}
I have the feeling that your number values from your input file are being read in as strings instead of ints. Using something like (int) should be able to help with this type of issue. You could also potentially use (integer) or intval() instead of (int) for the conversion part. More info about this can be found here.
Update:
After seeing CBroe's comment, I removed my earlier part about the string concatenation conjecture.
When checking the sumFromFileInput() function locally and using var_dump($number) to show the $number variable's type, I can verify that it is a string. This is why I still recommend using something like (int), like in my added lines of code earlier in this answer. Without doing that, I get PHP notices in PHP 7.3.19 for these values that read like: PHP Notice: A non well formed numeric value encountered in [...].
Interestingly enough, though, I still get a total of 54 (as an int) with your original posted code. This gets me to thinking: it would be interesting to see the code you used to call your sumFromFileInput() function, because perhaps that might help explain why your output was what now appears to me to be a running sum total of the $total.
Also, this might not be as important, but it looks like your $fileName parameter isn't currently being used in your sumFromFileInput() function. Maybe this could be connected in the future?
I have tried searching the forums but still unsure how to do this.
I am extracting a web link from a webpage, and the start and end are always the same but there is a variable i want to get.
E.g http://www.example.com/images/$VARIABLE/image.jpg
$position1 = http://www.example.com/images/
$position2 = image.jpg
I need to get the variable. On the webpage the $position 2 is listed more than once (image.jpg)
I have tried all sorts of things and nothing works so far.
Thank you
$begin = strpos($page, $position1) + strlen($position1);
$end = strpos($page, $position2);
$ImageName = substr($page, $begin, ($end - $begin));
I think the problem is that if image.jpg occurs before http://www.example.com/images/, then just trying to use your code won't work.
A slight fix would be to start the search for $position2 where you found the first part by adding a start point in the strpos() function...
$begin = strpos($page, $position1) + strlen($position1);
$end = strpos($page, $position2, $begin);
$ImageName = substr($page, $begin, ($end - $begin) - 1);
with
$page = "some test image.jpg some more text
blurb that is in the middle http://www.example.com/images/VARIABLE/image.jpg
some even more text image.jpg";
the code finds
VARIABLE
A regex as suggested by #user3783243 may also work, but you may also need a constraint of how long the parameter is likely to be.
I'm trying to make the fizzbuzz.php assignment from PHP and MySQL Web Development 5th Edition, page 193. I have typed it exactly as it is in the book, but I get a (T_CONSTANT_ENCAPSED_STRING) parse error (line 9) when I run it.
I have tried replacing yeild with echo, but then I get an improper function use error on line 27 (the foreach function).
I have tried escaping the " with \ but that gives me a syntax error, unexpected string.
I have tried using ' instead of " but get the enacapsed string error.
<?php
function fizzbuzz($start, $end)
{
$current = $start;
while ($current <= $end)
{
if ($current%3 == 0 && $current%5 == 0)
{
yield "fizzbuzz";
}
elseif ($current%3 == 0)
{
yield "fizz";
}
elseif ($current%5 == 0)
{
yield "buzz";
}
else
{
yield $current;
}
$current++;
}
}
foreach(fizzbuzz(1, 20) as $number)
{
echo $number.'<br />';
}
?>
Changing yeild to echo returns a string of numbers and fizz buzz strings but they are not in the order they are supposed to be and there is still a function error at line 27.
I may have something mistyped, but I've checked it over and over, and this is how it's written in the book.
This is too long for a comment.
I suspect that your version of PHP you are running this on, isn't able to support it, per testing your code online on http://sandbox.onlinephpfunctions.com/.
Test link saved with the error, version 5.0.4
Test link saved and working with version 5.6.29
It threw back the same error when using PHP 5.0.4.
You will need to upgrade your server if this is on a local machine. If it is hosted, you will need to contact the hosting provider to see if a newer version of PHP is available to you.
Edit:
Per the manual on PHP.net under "Note":
In PHP 5, a generator could not return a value: doing so would result in a compile error. An empty return statement was valid syntax within a generator and it would terminate the generator.
Edit #2:
(From comments)
Thank you for your help, and the links to the php sandbox, that will help me in the future. I ran phpversion() and it returned 5.4.45. It's a school server, so I'll ask them if they can upgrade it, or install PEAR on my laptop. – BackupXfer
Using version 5.4.45 also returned the same error, per the new test link. This feature is only available in PHP 5.5.0 and higher.
for php5
function fizzbuzz($start, $end)
{
for ($i=$start; $i<=$end; $i++)
{
$str = '';
if ($i % 3 == 0)
$str = 'Fizz';
if ($i % 5 == 0)
$str .= 'Buzz';
if (empty($str))
$str = $i;
echo $str.'<br>';
}
}
fizzbuzz(1, 20);
I'm trying to get a "live" progress indicator working on my php CLI app. Rather than outputting as
1Done
2Done
3Done
I would rather it cleared and just showed the latest result. system("command \C CLS") doesnt work. Nor does ob_flush(), flush() or anything else that I've found.
I'm running windows 7 64 bit ultimate, I noticed the command line outputs in real time, which was unexpected. Everyone warned me that out wouldn't... but it does... a 64 bit perk?
Cheers for the help!
I want to avoid echoing 24 new lines if I can.
Try outputting a line of text and terminating it with "\r" instead of "\n".
The "\n" character is a line-feed which goes to the next line, but "\r" is just a return that sends the cursor back to position 0 on the same line.
So you can:
echo "1Done\r";
echo "2Done\r";
echo "3Done\r";
etc.
Make sure to output some spaces before the "\r" to clear the previous contents of the line.
[Edit] Optional: Interested in some history & background? Wikipedia has good articles on "\n" (line feed) and "\r" (carriage return)
I came across this while searching for a multi line solution to this problem. This is what I eventually came up with. You can use Ansi Escape commands. http://www.inwap.com/pdp10/ansicode.txt
<?php
function replaceOut($str)
{
$numNewLines = substr_count($str, "\n");
echo chr(27) . "[0G"; // Set cursor to first column
echo $str;
echo chr(27) . "[" . $numNewLines ."A"; // Set cursor up x lines
}
while (true) {
replaceOut("First Ln\nTime: " . time() . "\nThird Ln");
sleep(1);
}
?>
I recently wrote a function that will also keep track of the number of lines it last output, so you can feed it arbitrary string lengths, with newlines, and it will replace the last output with the current one.
With an array of strings:
$lines = array(
'This is a pretty short line',
'This line is slightly longer because it has more characters (i suck at lorem)',
'This line is really long, but I an not going to type, I am just going to hit the keyboard... LJK gkjg gyu g uyguyg G jk GJHG jh gljg ljgLJg lgJLG ljgjlgLK Gljgljgljg lgLKJgkglkg lHGL KgglhG jh',
"This line has newline characters\nAnd because of that\nWill span multiple lines without being too long",
"one\nmore\nwith\nnewlines",
'This line is really long, but I an not going to type, I am just going to hit the keyboard... LJK gkjg gyu g uyguyg G jk GJHG jh gljg ljgLJg lgJLG ljgjlgLK Gljgljgljg lgLKJgkglkg lHGL KgglhG jh',
"This line has newline characters\nAnd because of that\nWill span multiple lines without being too long",
'This is a pretty short line',
);
One can use the following function:
function replaceable_echo($message, $force_clear_lines = NULL) {
static $last_lines = 0;
if(!is_null($force_clear_lines)) {
$last_lines = $force_clear_lines;
}
$term_width = exec('tput cols', $toss, $status);
if($status) {
$term_width = 64; // Arbitrary fall-back term width.
}
$line_count = 0;
foreach(explode("\n", $message) as $line) {
$line_count += count(str_split($line, $term_width));
}
// Erasure MAGIC: Clear as many lines as the last output had.
for($i = 0; $i < $last_lines; $i++) {
// Return to the beginning of the line
echo "\r";
// Erase to the end of the line
echo "\033[K";
// Move cursor Up a line
echo "\033[1A";
// Return to the beginning of the line
echo "\r";
// Erase to the end of the line
echo "\033[K";
// Return to the beginning of the line
echo "\r";
// Can be consolodated into
// echo "\r\033[K\033[1A\r\033[K\r";
}
$last_lines = $line_count;
echo $message."\n";
}
In a loop:
foreach($lines as $line) {
replaceable_echo($line);
sleep(1);
}
And all lines replace each other.
The name of the function could use some work, just whipped it up, but the idea is sound. Feed it an (int) as the second param and it will replace that many lines above instead. This would be useful if you were printing after other output, and you didn't want to replace the wrong number of lines (or any, give it 0).
Dunno, seemed like a good solution to me.
I make sure to echo the ending newline so that it allows the user to still use echo/print_r without killing the line (use the override to not delete such outputs), and the command prompt will come back in the correct place.
i know the question isn't strictly about how to clear a SINGLE LINE in PHP, but this is the top google result for "clear line cli php", so here is how to clear a single line:
function clearLine()
{
echo "\033[2K\r";
}
function clearTerminal () {
DIRECTORY_SEPARATOR === '\\' ? popen('cls', 'w') : exec('clear');
}
Tested on Win 7 PHP 7. Solution for Linux should work, according to other users reports.
something like this :
for ($i = 0; $i <= 100; $i++) {
echo "Loading... {$i}%\r";
usleep(10000);
}
Use this command for clear cli:
echo chr(27).chr(91).'H'.chr(27).chr(91).'J'; //^[H^[J
Console functions are platform dependent and as such PHP has no built-in functions to deal with this. system and other similar functions won't work in this case because PHP captures the output of these programs and prints/returns them. What PHP prints goes to standard output and not directly to the console, so "printing" the output of cls won't work.
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE);
function bufferout($newline, $buffer=null){
$count = strlen(rtrim($buffer));
$buffer = $newline;
if(($whilespace = $count-strlen($buffer))>=1){
$buffer .= str_repeat(" ", $whilespace);
}
return $buffer."\r";
};
$start = "abcdefghijklmnopqrstuvwxyz0123456789";
$i = strlen($start);
while ($i >= 0){
$new = substr($start, 0, $i);
if($old){
echo $old = bufferout($new, $old);
}else{
echo $old = bufferout($new);
}
sleep(1);
$i--;
}
?>
A simple implementation of #dkamins answer. It works well. It's a bit- hack-ish. But does the job. Wont work across multiple lines.
function (int $count = 1) {
foreach (range(1,$count) as $value){
echo "\r\x1b[K"; // remove this line
echo "\033[1A\033[K"; // cursor back
}
}
See the full example here
Unfortunately, PHP 8.0.2 does not has a function to do it. However, if you just want to clear console try this: print("\033[2J\033[;H"); or use : proc_open('cls', 'w');
It works in php 8.0.2 and windows 10. It is the same that system('cls') using c language programing.
Tried some of solutions from answers:
<?php
...
$messages = [
'11111',
'2222',
'333',
'44',
'5',
];
$endlines = [
"\r",
"\033[2K\r",
"\r\033[K\033[1A\r\033[K\r",
chr(27).chr(91).'H'.chr(27).chr(91).'J',
];
foreach ($endlines as $i=>$end) {
foreach ($messages as $msg) {
output()->write("$i. ");
output()->write($msg);
sleep(1);
output()->write($end);
}
}
And \033[2K\r seems like works correct.