Ik gebruik wat regex functies voor het splitsen en/of valideren van strings.

Nu lijkt echter dat wanneer de string langer is dan een x aantal karakters, dat ik een 'error 500 interne server fout' krijg. Met kortere strings is er echter geen probleem

Zowel de preg_match_all als de preg_split geven zo'n fout bij een te lange string.

<?php

$string = "UPDATE `#_module_webpage` SET `content` = 'Lorem ipsum..' WHERE `id` = '3' LIMIT 1;";

$expr = '/([^\']+)|(\'((\\\\.)|([^\']))+\')/i';
$matches = array();

preg_match_all($expr, $string, $matches);

print_r($matches);

?>

Weet iemand toevallig of dit opgelost kan worden (er kan zoveel geconfigureerd worden ;))
Geven je error logs misschien meer informatie? Apache zal toch wel ergens vermelden wat er mis ging...
Waarom doe je overigens een regex op een complete query ?

Wat doen die hekjes in je tabel namen ? waarom geen mooiere namen

Wat doen die back-ticks in je query ? gewoon wegpleuren
Baarr schreef op 13.04.2007 10:33
Waarom doe je overigens een regex op een complete query ?

Wat doen die hekjes in je tabel namen ? waarom geen mooiere namen

Wat doen die back-ticks in je query ? gewoon wegpleuren


Die backticks kan je anders wel gebruiken voor gereserveerde worden in mysql... Kan je die worden toch nog gebruiken:) link

[edit]Moet ie die worden wel gebruiken anders hebben die backticks inderdaad geen nut[/edit]
@Pholeron

Ik weet niet precies hoe het zit, maar die error heeft volgens mij niet met de duur van je uitvoer te maken. Je kan wel proberen om je string in stukjes te knippen. (gebruik hiervoor bijvoorbeeld het script dat strings afkort op een aantal tekens, maar wel de woorden in tact laat. Staat in de script lib)

[edit][offtopic]
@mebus

Het is voor jezelf veel gemakkelijker om gewoon goede namen te kiezen die niet overeenkomen met gereserveerde woorden. Een simpele query kan daardoor toch verkeerd worden gelezen/ begrepen wanneer je hem terugleest, en als je een keer backticks vergeet werkt het niet, bijv:

Een setup voor een tabel met shows die worden gegeven. Waarbij het ook mogelijk is om de weergave van een show te blokkeren, omdat die bijv nog niet vast staat.

TABLE: Show
id
name
description
show (laat zien of niet)

Snap je wat ik bedoel? Als je nu een show (weergave) in MySQL zou willen doen van deze tabel, dan krijg je een query waarin het woord Show nogal vaak voorkomt, wat voor je eigen overzicht niet handig is.

Kies dan als tabelnaam bijvoorbeeld: Show_Info (heb je geen backticks bij nodig, en je tabelnaam beschrijft ook nog eens beter wat voor informatie erin zit)
En voor de kolom show -> maak daar bijvoorbeeld viewable van. Ook hierbij heb je dan geen backticks nodig, en het beschrijft ook het doel van die kolom beter.

Door op zo'n manier met je database om te gaan hou je je tabellen en query's eigenlijk heel eenvoudig. En door juiste namen te gebruiken kan je ook heel snel de bedoeling van een query begrijpen, zonder dat je daar andere informatie dan de query zelf voor nodig bent.

Verder lijkt het me beter maar weer ontopic verder te gaan. :)
[/offtopic][/edit]
Euhm, waarom dit alles:

De queries vorden verwerkt in een CMS systeem.
Dit CMS hanteerd een tabel-naam-prefix die in queries steeds wordt aangeduid met een hekje.

Deze functie vervangt vervolgens de hekjes met de geconfigureerde prefix.

Om te voorkomen dat hekjes in data niet worden vervangen door de ingestelde prefix, wordt in de query de boel gesplits naar waarden tussen single quotes (data), en alle overige waarden (tabelnamen e.d.). Op deze laatste wordt een str_replace losgelaten die alle hekjes vervangt door de ingestelde prefix.

Op mijn server gaat dat goed, maar op een andere server (waar ik het CMS heb geinstalleerd) treden er problemen op als de query te lang is.
Dit is trouwens de database class die ik gebruik binnen het CMS.

Zie de __setPrefix() functie onderin..



<?php

class Database
{
var $resource; // Stores the resource identifier of the connection to the SQL server.

var $user; // username
var $pass; // password
var $name; // name of the database
var $host; // host (An IP or 'localhost')
var $prefix; // Table prefix (replace "#" for "[prefix]").
var $charset; // communication charset


// Creates a new database
function Database($user, $pass, $name, $host = "localhost", $prefix = false, $charset = false)
{
// Connect to database server
if($this->resource = mysql_connect($host, $user, $pass))
{
// Select a database on the MySQL Server
if(mysql_select_db($name))
{
// Locked to requested database
$this->user = $user;
$this->pass = "**********"; // $this->pass = $pass;
$this->name = $name;
$this->host = $host;
$this->prefix = $prefix;
$this->charset = $charset;

if($charset)
{
// Set communication characterset
$sQuery = "SET CHARACTER SET '" . $charset . "';";
$this->execute($sQuery, __FILE__, __LINE__);
}
}
else
{
// Error while selecting database
exit("Error while connecting to database\nFile: " . __FILE__ . ", Line: " . __LINE__ . ".");
}
}
else
{
// Error while connection to server
exit("Error while connecting to database.\nFile: " . __FILE__ . ", Line: " . __LINE__ . ".");
}
}

// Function to execute a SQL stetement (eg. DELETE/INSERT/UPDATE).
function execute($sQuery, $sFile = false, $iLine = 0)
{
$sQuery = $this->__setPrefix($sQuery);

if(mysql_query($sQuery, $this->resource))
{
return true;
}
else
{
$this->__reportError($sQuery, $sFile, $iLine);
}
}

// Returns the list of fieldnames within a table.
function getColumns($sTableName, $bSort = true)
{
$aColumns = array();

$sQuery = "SHOW COLUMNS FROM `" . $sTableName . "`;";
$rsResults = $this->getRecords($sQuery, true, __FILE__, __LINE__);

for($i = 1; $i < sizeof($rsResults); $i++)
{
$aColumns[] = $rsResults[$i][$rsResults[0][0]];
}

if($bSort)
{
if(sizeof($aColumns) > 1)
{
usort($aColumns, "strcasecmp");
}
}

return $aColumns;
}

// Returns the last created record-id (only works after an INSERT-statement).
function getId()
{
return mysql_insert_id($this->resource);
}

// Returns upto 1 record after running a SQL-statement.
// No results will return FALSE.
function getRecord($sQuery, $sFile = false, $iLine = 0)
{
$rsResults = $this->getRecords($sQuery, false, $sFile, $iLine);

if(sizeof($rsResults) > 0)
{
return $rsResults[0];
}

return false;
}

// Returns all records after running a SQL-statement.
// The columnnames are stored at index
// No results will return an array with only the columnnames (at index 0).
function getRecords($sQuery, $bAddHeader = false, $sFile = false, $iLine = 0)
{
$sQuery = $this->__setPrefix($sQuery);
$aResults = array();

if($rsResults = mysql_query($sQuery, $this->resource))
{
if($bAddHeader)
{
$aHeader = array();

if(mysql_num_rows($rsResults) > 0)
{
$aResult = mysql_fetch_array($rsResults, MYSQL_ASSOC);

foreach($aResult AS $sKey => $sVal)
{
$aHeader[] = $sKey;
}

$aResults[] = $aHeader;
$aResults[] = $aResult;
}
else
{
while($aField = mysql_fetch_field($rsResults))
{
$aHeader[] = $aField->name;
}

$aResults[] = $aHeader;
}
}

while($aResult = mysql_fetch_array($rsResults, MYSQL_ASSOC))
{
$aResults[] = $aResult;
}

mysql_free_result($rsResults);
}
else
{
$this->__reportError($sQuery, $sFile, $iLine);
}

return $aResults;
}

// Returns the list of tables within the current database.
function getTables($bSort = true)
{
$aTables = array();

$sQuery = "SHOW TABLES FROM `" . $this->name . "`;";
$rsResults = $this->getRecords($sQuery, true, __FILE__, __LINE__);

for($i = 1; $i < sizeof($rsResults); $i++)
{
$aTables[] = $rsResults[$i][$rsResults[0][0]];
}

if($bSort)
{
if(sizeof($aTables) > 1)
{
usort($aTables, "strcasecmp");
}
}

return $aTables;
}


// Returns true if a column exists, false otherwise.
// Note: Columnnames are CASE SENSITIVE in MySQL!!
function isColumn($sTableName, $sFieldName)
{
// Get all fields withing table
$aFields = $this->getColumns($sTableName);
return in_array($sFieldName, $aFields);
}

// Returns true if a field table, false otherwise.
// Note: Tablenames are CASE SENSITIVE in MySQL!!
function isTable($sTableName)
{
if($this->prefix !== false)
{
if(strcasecmp(substr($sTableName, 0, 1), '#') === 0) // Tablename starts with #
{
$sTableName = $this->prefix . substr($sTableName, 1);
}
}

// Get all tables withing database
$aTables = $this->getTables();
return in_array($sTableName, $aTables);
}

// Print SQL output into a HTML based table.
// Note: This function was added to support the testing of SQL queries.
function printSQL($sQuery)
{
// Execute SQL and retrieve records
$rsRecords = $this->getRecords($sQuery, true, __FILE__, __LINE__);

$result = highlight_sql($sQuery, true)
. '<table border="1" cellpadding="5" cellspacing="0">';

// Create header
$result .= '<tr>';

for($col = 0; $col < sizeof($rsRecords[0]); $col++)
{
$result .= '<th align="left" valign="top">' . str_replace("\n", "<br>", htmlentities($rsRecords[0][$col])) . '&nbsp;</th>';
}

$result .= '</tr>';

// Create records
for($row = 1; $row < sizeof($rsRecords); $row++)
{
$result .= '<tr>';

for($col = 0; $col < sizeof($rsRecords[0]); $col++)
{
$result .= '<td align="left" valign="top">' . str_replace("\n", "<br>", htmlentities($rsRecords[$row][$rsRecords[0][$col]])) . '&nbsp;</td>';
}

$result .= '</tr>';
}

$result .= '</table>';

// Print output
exit($result);
}

// Replace tablenames with # for the given prefix
function __setPrefix($query)
{
$result = '';

if($this->prefix !== false)
{
$expr = '/(\'((\\\\.)|[^\\\\\\\'])*\')|(\`((\\\\.)|[^\\\\\\\`])*\`)|([a-z0-9_]+)|([\s\n]+)|(.)/i';
preg_match_all($expr, $query, $matches);

for($i = 0; $i < sizeof($matches[0]); $i++)
{
if(strcasecmp($match = $matches[0][$i], "") !== 0)
{
if(strcasecmp(substr($match, 0, 1), "'") === 0)
{
$result .= $match;
}
else
{
$result .= str_replace("#", $this->prefix, $match);
}
}
}
}

return $result;
}

function __reportError($sQuery, $sFile = false, $iLine = 0)
{
$result = '<h1>Error in query:</h1>'
. '<p><b>Query:</b></p>'
. (function_exists('highlight_sql') ? highlight_sql($sQuery, true) : $sQuery)
. '<p><b>Error number:</b><br>' . htmlentities(mysql_errno($this->resource)) . '</p>'
. '<p><b>Error message:</b><br>' . htmlentities(mysql_error($this->resource)) . '</p>';

if($sFile !== false)
{
$result .= '<h1>Query invoked in:</h1>'
. '<p><b>File:</b><br>' . htmlentities($sFile) . '</p>'
. '<p><b>Line:</b><br>' . htmlentities($iLine) . '</p>';
}

exit($result);
}
}

?>
@Robert zelf gebruik ik geen backticks in me query's of tabellen:) En als ik een gereserveerd woord tegenkom dan verzin ik er gewoon een andere voor:)

Maar ik snap wat je bedoelt:)
<offtopic>

Over backticks:

Backticks zijn in mijn ogen een standaard onderdeel van de SQL syntax..

Net als dat de openingtag van PHP officieel "< ? php" is, en niet "< ?". Toch werken ze allebei ;)

Door backticks voor kolomnamen expliciet te gebruiken worden (in mijn ogen) queries leesbaarder. 't is een questie van smaak, gewoonte en (mogelijk) gemakzucht dan wel het een of het ander te gebruiken..



Tevens worden door gebruik van backticks spaties, speciale tekens en gereserveerde 'keywords' toegankelijk als/in tabelnamen. Niet dat ik hierbij een discussie aan wil gaan of het gebruik van spaties o.i.d. aan te raden is in een tabelnaam.. maar de 'technische beperking' is in ieder geval geen excuus meer..

</offtopic>
Ik heb wat verder gezocht maar 'k kon geen zinnige verklaring vinden :( Dus ik heb in php een oplossing geschreven..

Wat kunnen die regex toch efficient zijn ;)

Vergelijk
<?php

function __splitQuery($sQuery)
{
$expr = '/(\'((\\\\.)|[^\\\\\\\'])*\')|(\`((\\\\.)|[^\\\\\\\`])*\`)|([a-z0-9_]+)|([\s\n]+)|(.)/i';
preg_match_all($expr, $sQuery, $matches);

return $matches[0];
}

?>
maar eens met de code:
<?php

function __splitQuery($sQuery)
{
$aResult = array();

$bEscaped = false;
$bQuoted = false;
$bBackticked = false;

$sBuffer = '';
$iLength = strlen($sQuery);

for($i = 0; $i < $iLength; $i++)
{
$char = $sQuery[$i];

if((strcmp($char, "'") === 0) && ($bEscaped === false) && ($bBackticked === false)) // Quotes
{
if($bQuoted)
{
$sBuffer .= $char; // Add closing quote to buffer
$aResult[] = $sBuffer; // Add buffer to result
$sBuffer = ''; // Clear buffer

$bQuoted = false; // Set quoted flag
}
else
{
$aResult[] = $sBuffer; // Add buffer to result
$sBuffer = ''; // Clear buffer
$sBuffer .= $char; // Add opening quote to buffer

$bQuoted = true; // Set quoted flag
}
}
elseif((strcmp($char, "`") === 0) && ($bEscaped === false) && ($bQuoted === false)) // Backticks
{
if($bBackticked)
{
$sBuffer .= $char; // Add closing backtick to buffer
$aResult[] = $sBuffer; // Add buffer to result
$sBuffer = ''; // Clear buffer

$bBackticked = false; // Set backtick flag
}
else
{
$aResult[] = $sBuffer; // Add buffer to result
$sBuffer = ''; // Clear buffer
$sBuffer .= $char; // Add opening backtick to buffer

$bBackticked = true; // Set backtick flag
}
}
else
{
// Backslashes
if((strcmp($char, "\\") === 0) && ($bQuoted || $bBackticked))
{
$bEscaped = ($bEscaped === false);
}
else
{
$bEscaped = false;
}

$sBuffer .= $char;
}
}

if(strlen($sBuffer) > 0)
{
$aResult[] = $sBuffer;
}

return $aResult;

}

?>
Ja, dat scheelt nogal een slok op een borrel. Maar misschien is de code van jouw eigen functie wel veel korter dan de source code voor preg_match_all. (vermoed van wel)

Reageren