Coś wydajniejszego niż wyrażenia regularne (preg_replace_callback)

0

Witam.
Szukam czegoś oszczędniejszego niż preg_replace_callback - gdy jest duży string, serwer się wysypuje.

Muszę to co jest w tagach <?php oraz ?> (może być ich nawet kilkadziesiat w jednym stringu) przesłać przez

"<phpcode><!--PHP".htmlspecialchars(TUTENKOD, ENT_QUOTES|ENT_NOQUOTES, $charset).' PHP--></phpcode>';

jakieś pomysły?

0

Matko, jak duzy jest ten string, ze sie serwer wysypuje ;) Dobrze by bylo, gdybys przedstawil to wyrazenie regularne.

No i zamiast preg_replace_callback() mozesz uzyc zwyklego preg_replace() z dyrektywa /e

0

Ymm, okazało się że nawet preg replace callback radzi sobie z tym stringiem, nie wiem czemu własnie tego się uczepiłem.
Prawdziwa zmora to :

		/* <node attr='< ?php ? >'> extra space added to save highlighters */
		$regexes = array(
			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^\']*)\'@s',
			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^"]*)"@s',
		);
		foreach($regexes as $regex){
			while (preg_match($regex, $content)){ // preg match wysiada
					//exit;
					$content = preg_replace_callback(
						$regex,
						create_function('$m',
							'return $m[1].$m[2].$m[3]."<?php "
								.str_replace(
									array("%20", "%3E", "%09", "&#10;", "&#9;", "%7B", "%24", "%7D", "%22", "%5B", "%5D"),
									array(" ", ">", "	", "\n", "	", "{", "$", "}", \'"\', "[", "]"),
									htmlspecialchars_decode($m[4])
								)
								." ?>".$m[5].$m[2];'
						),
						$content
					);
				}
			}
		return $content;

Jak funkcja preg replace callback daje rady, to spróboje to przerobić. Tylko teraz potrzebuje jednej podpowiedzi:

'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^\']*)\'@s', 
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^"]*)"@s',

Czy dobrze rozczytałem te wyrażenia?.
1 i 2 Wybiera tekst który jest pomiędzy :
<?php a ?>

0

No tak: uzywasz najpierw preg_match() a potem preg_replace_callback() - niepotrzebnie.

function foo($matches[1])
{
	// operacje na kodzie PHP:
	return htmlspecialchars($matches[1]);
}

$text = preg_replace_callback('#<\?php(.*)\?>#is', 'foo', $text);

Co do samego regexpa: jak widzisz, ja uzylem prostego (.*). Twoj regexp moze i jest lepszy, ja nie czuje sie na tyle biegly w regexpach aby doradzac w tym temacie wiec moze ktos inny sie wypowie

0

Tak, tak. Właśnie przerabiam phpQuery - autor ostatnio modyfikował bibliotekę w lutym poprzedniego roku. Już prawie wszystko poprawiłem, lecz został jeszcze metoda $this->php(); - autor bardzo dobrze zna się na wyrażeniach, lecz zbyt pochopnie sobie utrudnia życie.

Bardzo mi zależy teraz na jednym - rozkodowaniu : @(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^\']*)\'@s

0

Zrezygnuj z create_function w pętli. Ile przelotów, tyle funkcji jednorazowego użytku tworzysz - z tego co widzę wystarczy ją utworzyć raz. Albo jeszcze lepiej olać w ogóle create_function i zrobić normalną funkcję/metodę prywatną.

0

@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^\']*)\'@s -> oznacza pobranie wszystkich

<node attr="&lt;?php TO JEST POBIERANE ?&gt;" attr2="&lt;?php TO JEST POBIERANE 2 ?&gt;" />

Mam na razie:

$string = "<node attr='&lt;?php echo 'test'; ?&gt;' attr2='&lt;?php echo 'test2'; ?&gt;' />";

function foo($matches){
var_dump($matches);
}
$text = preg_replace_callback('#<(.*?)&lt;\?php(.*?)\?&gt;(.*?)>#is', 'foo', $string);

Wynikiem tego jest:

array(4) {
  [0]=>
  string(79) "<node attr='&lt;?php echo 'test'; ?&gt;' attr2='&lt;?php echo 'test2'; ?&gt;' />"
  [1]=>
  string(11) "node attr='"
  [2]=>
  string(14) " echo 'test'; "
  [3]=>
  string(39) "' attr2='&lt;?php echo 'test2'; ?&gt;' /"
}

Teraz pytanie zamykające temat;
Jak widać pobrane zostało tylko pierwszy kod php " echo 'test';" . Jak zrobić by zostało też pobrane ten drugi kod "echo 'test2';" i tak w nieskonczonosc?

1

Najprościej byłoby olać wyrażenia regularne i użyć zapytania XPath:

<pre>
<?php

$string = "<html>
  <foo someattr='&lt;?php echo 'test3'; ?&gt;'>
    <bar otherattr=\"&lt;?php echo 'test3'; ?&gt;\" />
  </foo>
  <foo wrongattr='php'/>
  <node attr='&lt;?php echo 'test'; ?&gt;' attr2='&lt;?php echo 'test2'; ?&gt;' />
</html>";

libxml_use_internal_errors( true );
$doc = new DOMDocument();
$doc->loadHTML( $string );

$xpath = new DOMXPath( $doc );
$query = "//attribute::*[contains(., '<?php')]"; // &lt; automatycznie tłumaczony na <
$attributes = $xpath->query( $query );

foreach( $attributes as $attribute )
{
    echo $attribute->name . ": ";
    echo htmlspecialchars( $attribute->value ) . "\n";
}

?>
</pre>

Pojawia się jednak problem - apostrofy przy echo kolidują z tymi od atrybutów i wszystko się sypie :( Dodatkowo DOM może być mniej wydajny od wyrażeń regularnych.

Jako rozwiązanie proponuję 2 wyrażenia regularne. To które masz wyciąga ci elementy HTML, które w przynajmniej jednym atrybucie mają kod PHP. Teraz w funkcji foo() dodaje jeszcze jednego preg_replace_callback, który wyciągnie i zamieni kod pomiędzy &lt;?php a ?&gt; - zrobi to dla każdego atrybutu, wiec problem się rozwiąże.

0

wlasnie przygotowuje kod do wdrożenia do DOM document (zobacz -PHPquery). W DOM document nie moze być kod PHP, trzeba najpierw go przekonwertowac przez htmlspecialchars nastepnie jak pobawimy sie w DOM'ie, znow odwrocic proces przez htmlspecialchars decode.

1 użytkowników online, w tym zalogowanych: 0, gości: 1