[PHP] string te groot voor preg_replace?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
Via file_get_contents() krijg ik een string van een pagina, deze string kan nogal groot zijn naarmate de pagina groot is.

Met die string wil ik een simpele preg_replace uitvoeren. (Bijv alle <br> weghalen)
PHP:
1
$str = preg_replace("/\<br\>/s", "", $strSubject);

Maar wat gebeurt en nu: als de string groter of gelijk is dan 100295 tekens precies, krijg ik niets terug van preg_replace en is $str leeg.
Maar: als de string kleiner is dan 100295 doet preg_replace het goed.

Ik draai zelf apache, hier wat settings die mogelijk er mee te maken hebben:
max_execution_time = 0
max_input_time = 0
memory_limit = 64M


Nog wat research:
- PHP.net zegt zelf dat strings zo groot mogen zijn als het kan:
http://nl3.php.net/string
It is no problem for a string to become very large. There is no practical bound to the size of strings imposed by PHP, so there is no reason at all to worry about long strings.
- De PCRE heeft de volgende regel:
http://www.pcre.org/pcre.txt (Limitations)
The maximum length of a subject string is the largest positive number that an integer variable can hold
Een "largest positive number" van een int lijkt me groter kunnen dan 100295...


-------------------------------------

Edit:

De topic beschrijving bevat lichtelijk verkeerde informatie.

Het probleem doet zich namelijk alleen op als het resultaat van de functie preg_replace groter is dan 99990 tekens.

De $subjectString mag dus wel groot zijn, maar het resultaat moet minder dan 99990 tekens zijn.

[ Voor 11% gewijzigd door verytallman op 17-03-2007 02:09 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Alleen <br>'s weghalen doe je niet met preg_replace maar met str_replace, dat is wat efficiënter en oogt wat duidelijker. :P

Over je probleem: een string van 100KB zou geen enkel probleem moeten zijn, ik heb wel eens veel grotere strings door die functie gehaald. Weet je zeker dat je probleem niet ergens anders zit? :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
Die <br>'s weghalen is maar een voorbeeld.

Het probleem lijkt toch echt op die 100295 bytes/tekens te zitten.
Ik heb zelf een input.html bestand gemaakt en daar kan ik precies testen/zien dat bij >= 100295 de functie niets retourneert, en bij < 100295 de functie wel het resultaat retourneert.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

En dat gebeurt bij elke regexp, ongeacht wat je opzoekt?

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Blackbird-ce
  • Registratie: September 2005
  • Laatst online: 20:05
lijkt me geen fout in de functie zelf:
PHP:
1
2
3
4
5
6
7
8
9
10
<?php
for($i=0;$i<30000;$i++)
{
    $longString=$longString."lang ";
}

    echo "lengte origineel: ".strlen($longString);
    $newString = preg_replace("/l/s", "", $longString); 
    echo "<br>lengte nieuw: ".strlen($newString);
?>


deze komt netjes met:
lengte origineel: 150000
lengte nieuw: 120000

[ Voor 11% gewijzigd door Blackbird-ce op 17-03-2007 10:00 ]


Acties:
  • 0 Henk 'm!

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 09-09 15:24
Weet je zeker dat je string geen newlines bevat en je pattern dus een multiline modifier moet hebben?
PHP:
1
$str = preg_replace("/\<br\>/sm", "", $strSubject);

Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
Het topic moet worden aangepast;

Ik zal twee bestanden geven waarvan de ene het wel doet en de ander het niet.
Het verschil zit in 1 teken.
http://www.few.vu.nl/~jpstout/preg_test/strlen_100294.html
http://www.few.vu.nl/~jpstout/preg_test/strlen_100293.html

Dit is de code om de preg_replace te doen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Het html bestand met 100294 tekens proberen:

$url_100294 = 'strlen_100294.html';
$strUrl_100294 = file_get_contents($url_100294, false);

echo '<br>strlen voor: '.strlen($strUrl_100294).'<br>'; 
// Het head gedeelte weghalen
$strUrl_100294 = preg_replace("/\<head\>.*\<\/head\>/smi", "", $strUrl_100294); 
echo '<br>strlen na: '.strlen($strUrl_100294).'<br>';


// Het html bestand met 100293 tekens proberen:

$url_100293 = 'strlen_100293.html';
$strUrl_100293 = file_get_contents($url_100293, false);

echo '<br>strlen voor: '.strlen($strUrl_100293).'<br>'; 
// Het head gedeelte weghalen
$strUrl_100293 = preg_replace("/\<head\>.*\<\/head\>/smi", "", $strUrl_100293); 
echo '<br>strlen na: '.strlen($strUrl_100293).'<br>';


Als ik het script uitvoer op mijn eigen pc werkt het html bestand van 100294 tekens het niet en die met 100293 tekens het wel.

MAAR, voer ik het script uit op een hosting account met linux, doen ze het allebei !

Ik krijg ook een andere uitvoer op mijn eigen pc dan op me hosting. Maar dat zal wel met het os te maken hebben.

Mijn uitvoer:
strlen voor: 100294
strlen na: 0
strlen voor: 100293
strlen na: 100162

Op me hosting:
strlen voor: 99323
strlen na: 99198
strlen voor: 99322
strlen na: 99197

Op mijn eigen pc draai ik Xampp op windows xp.

Ik ben ook zeer benieuwd hoe dit script draait op servers van andere mensen.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

beetle71 schreef op zaterdag 17 maart 2007 @ 12:01:
Weet je zeker dat je string geen newlines bevat en je pattern dus een multiline modifier moet hebben?
PHP:
1
$str = preg_replace("/\<br\>/sm", "", $strSubject);
multiline heeft enkel betrekking op de betekenis van ^ en $ en heeft hier niets mee te maken.
In fact, de linespan modifier is hier ook niet van belang aangezien die enkel betrekking heeft op de betekenis van de .
Zelfs de escapetekens voor de < en > zijn hier overbodig, dus uiteindelijk is dit voldoende:
PHP:
1
$str = preg_replace('/<br>/', '', $strSubject);

maar je kan dan inderdaad beter str_replace gaan gebruiken want het is niet echt een expressie ;)

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Acolyte
  • Registratie: Oktober 2002
  • Laatst online: 28-08-2024

Acolyte

Lid

verytallman schreef op zaterdag 17 maart 2007 @ 16:33:
Op mijn eigen pc draai ik Xampp op windows xp.

Ik ben ook zeer benieuwd hoe dit script draait op servers van andere mensen.
Ik draai WAMP 5. Ik krijg gewoon

strlen voor: 99323

strlen na: 99198

strlen voor: 99322

strlen na: 99197

Hoor :) niets mis mee.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Hier op win2k met PHP 4.4.4:

strlen voor: 100294
strlen na: 100163
strlen voor: 100293
strlen na: 100162

Het verschil met je hosting ligt 'm trouwens aan de conversie van windows newlines naar *nix newlines bij het uploaden ;)

Welke versie PHP heb je draaien?

[ Voor 7% gewijzigd door crisp op 17-03-2007 17:05 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
crisp schreef op zaterdag 17 maart 2007 @ 17:04:
Welke versie PHP heb je draaien?
PHP Version 5.2.0

Er begin te denken aan een setting in me configuratie want ik draai dezelfde code als jullie.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

PHP 5 lijkt een aantal nieuwe settings te hebben in de php.ini mbt PCRE, o.a. pcre.backtrack_limit en pcre.recursion_limit

Ik ben zelf ook al eerder tegen problemen aangelopen met expressies die het in PHP 4.x nog prima deden maar in PHP 5(.2) niet meer.

Echo eens een preg_last_error() na je preg_replace

funny thing is dat ik door een bugreport eigenlijk verantwoordelijk ben voor deze nieuwe features in PHP 5.2 :P

[ Voor 14% gewijzigd door crisp op 17-03-2007 17:28 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
crisp schreef op zaterdag 17 maart 2007 @ 17:25:
PHP 5 lijkt een aantal nieuwe settings te hebben in de php.ini mbt PCRE, o.a. pcre.backtrack_limit en pcre.recursion_limit

Echo eens een preg_last_error() na je preg_replace
[/small]
Ik kan geen settings vinden in de php.ini waar de woorden pcre of backtrace in voor komen

Bij de preg_replace waar het fout gaat geeft de preg_last_error() een 2 als foutmelding, maar waar dat voor staat weet ik nog niet

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Dan geldt blijkbaar de default waarde. ;) Heb je die errorcode al eens vergeleken met de predefined constants?

{signature}


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
Gelukt :)

Die 2 nieuwe pcre settings moet je inderdaad in de php.ini zetten en flink verhogen

pcre.backtrack_limit = 1000000
pcre.recursion_limit = 1000000

Normaal staan die settings op 100.000 , wat geen toeval was aangezien die functie preg_replace bij mij niet werkte bij > 100294 tekens.


Edit: wel vervelend dat je met zoiets weer 2 dagen bezig bent.... |:(

[ Voor 11% gewijzigd door verytallman op 17-03-2007 18:09 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Uiteindelijk een configprobleem, dus ik zet je topic even elders neer. :P

PRG>>DTE

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

De defaults voor backtrack_limit en recursion_limit in PHP 5.2 zijn ook veels te beperkt. Default gebruikt PCRE zelf 10.000.000 voor beide settings.

Verder is de benaming 'backtrack_limit' fout; het gaat volgens mij namelijk niet om backtracking maar om het aantal keren dat PCRE een match probeert uit te voeren - dat hoeft niet noodzakelijk een match gedurende een backtrack te zijn. Ik vermoed dat dit ook fout gaat in PHP 5.2 met default settings:

PHP:
1
2
$a = str_repeat('a', 100024);
$b = preg_replace('/a/', 'b', $a);


Kan iemand bovenstaande bevestigen in PHP 5.2? - in dat geval wil ik er wel een bugreport aan wijden :)

[ Voor 9% gewijzigd door crisp op 17-03-2007 19:18 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Met PHP 5.2.0 en de defaultwaarden voor die variabelen krijg ik deze uitvoer:
code:
1
string(100024) "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

bij deze code:
PHP:
1
2
3
$a = str_repeat('a', 100024);
$b = preg_replace('/a/', 'b', $a);
var_dump($b);

Lijkt me aardig te kloppen. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Dat zou natuurlijk geoptimaliseerd kunnen zijn in PCRE.
Blijkbaar speelt de match-all directive (dot) een rol bij het aantal keer dat PCRE match() moet doen. Het voorbeeld van de TS is toch redelijk simpel en zou m.i. niet zo snel tegen een limiet aan moeten lopen - ongeacht of PCRE de matching nu dmv backtracking doet of niet. In ieder geval is er binnen PCRE geen setting die puur betrekking heeft op backtracking...

How about this:
PHP:
1
2
$a = 'baab' . str_repeat('a', 100024);
$b = preg_replace('/b.*b/', '', $a);

?

[ Voor 12% gewijzigd door crisp op 17-03-2007 19:44 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

crisp schreef op zaterdag 17 maart 2007 @ 19:43:
How about this:
PHP:
1
2
$a = 'baab' . str_repeat('a', 100024);
$b = preg_replace('/b.*b/', '', $a);

?
Dan is $b een nullpointer. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

-NMe- schreef op zaterdag 17 maart 2007 @ 19:58:
[...]

Dan is $b een nullpointer. :P
Mooi, dan ga ik de mensjes bij PHP daarmee om de oren slaan :P

et voila: http://bugs.php.net/bug.php?id=40846

[ Voor 10% gewijzigd door crisp op 17-03-2007 20:21 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 18-08 18:12
Ha, dat ik nog mag meemaken dat mijn probleem op GoT uiteindelijk als bug report op php.net komt :P

Thx allen voor de hulp!

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

verytallman schreef op zaterdag 17 maart 2007 @ 22:29:
Ha, dat ik nog mag meemaken dat mijn probleem op GoT uiteindelijk als bug report op php.net komt :P

Thx allen voor de hulp!
Jij ook bedankt; ik weet nu ook waarom een reguliere expressie van mij op onze test-omgeving ineens fout ging nadat we daar PHP 5.2 hadden geinstalleerd :)

Intentionally left blank

Pagina: 1