diff --git a/README.md b/README.md index 405bade..d674b1f 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,17 @@ declare @Fruit varchar(100) = ?; -- Options: Apple=0,Orange=1,Banana=2 ``` The above will still allow a user to select a fruit's name from the dropdown, but only one of the corresponding values 0, 1, or 2 will be sent to the query as a `varchar(100)`. + +--- + +### SQL Row and Column Hinting + +All data with column names starting with an underscore `_` will be hidden from the output. To have finer control of how a row or cell of data appears, you can select and position special columns to control how the output appears. + +* `__NextCellClass` — Apply this HTML class to the very next data cell + + **Note:** To apply more than one `__NextCellClass` hint, additional identifiers must be used, e.g. `__NextCellClass0` or `__NextCellClassXYZ`. + +* `__RowClass` — Apply this HTML class to the entire row and all data cells. + +* `__Section` — Use to categorize similar and subsequent rows under a section with this name. diff --git a/pages/run.php b/pages/run.php index 84202db..4b0fe3b 100644 --- a/pages/run.php +++ b/pages/run.php @@ -4,9 +4,6 @@ global $varRows; $strQueryDir = "files/sql"; - - // $varFiles = is_dir($strQueryDir)? scandir($strQueryDir) : []; - // $varFiles = array_diff($varFiles, [".", ".."]); function removeQueryDir(&$strInput) { @@ -39,88 +36,75 @@ $strFileDataSource = file_get_contents("{$strQueryDir}/{$strSelection}"); $strFileData = $strFileDataSource; - // Translate occurrences of {{ Date: next monday }} into yyyy-MM-dd format: - // Can be used in string literals or default values in comments! - preg_match_all( - "/\{\{\s*?Date\:\s*?(.*)\s*?\}\}/i", - $strFileData, - $varDateReplacements); - - for ($i = 0; $i < count($varDateReplacements[0]); $i++) + $fncReplaceDate = function($strInput) { - try - { - $strMatch = $varDateReplacements[0][$i]; - $strMatchSafe = preg_quote($strMatch); - $strDateString = $varDateReplacements[1][$i]; - $strFileData = preg_replace( - "/{$strMatchSafe}/i", - date_create($strDateString)->format("Y-m-d"), - $strFileData); - } - catch (Exception $x) {} - } + return + date_create($strInput) + ->format("Y-m-d"); + }; - // WARNING: Can be abused. - // Translate occurrences of {{ SQL: select 'test' }} into the string value of the first cell of the first row: - // Can be used in string literals or default values in comments! - preg_match_all( - "/\{\{\s*SQL\:\s*(.*)\s+?\}\}/i", - $strFileData, - $varSQLReplacements); - - for ($i = 0; $i < count($varSQLReplacements[0]); $i++) + $fncReplaceSQL = function($strSQL) { - try - { - $strMatch = $varSQLReplacements[0][$i]; - $strMatchSafe = preg_quote($strMatch); - $strSQLString = $varSQLReplacements[1][$i]; - $varTempRows = $c->query($strSQLString); + global $c; + $varRows = $c->query($strSQL); - //Respond::json($varTempRows); + if (count($varRows) > 0) + foreach ($varRows[0] as $k => $v) + return $varRows[0][$k]; + }; - $strFirstCell = ""; - if (count($varTempRows) > 0) - foreach ($varTempRows[0] as $k => $v) - { - $strFirstCell = $varTempRows[0][$k]; - break; - } - - $strFileData = preg_replace( - "/{$strMatchSafe}/i", - $strFirstCell, - $strFileData); - } - catch (Exception $x) {} - } - - // $_SERVER Key replacements: - preg_match_all( - "/\{\{\s*([A-Z_]{1,})\s*\}\}/i", - $strFileData, - $varServerKeyReplacements); - - //Respond::json($_SERVER); - - for ($i = 0; $i < count($varServerKeyReplacements[0]); $i++) + $fncReplaceServer = function($strInput) { - try - { - $strMatch = $varServerKeyReplacements[0][$i]; - $strMatchSafe = preg_quote($strMatch); - $strKey = $varServerKeyReplacements[1][$i]; + // Take no chances on possible SQL injection: + $strValue = $_SERVER[$strInput]; + $strValue = preg_replace("/\'/i", "", $strValue); - if (array_key_exists($strKey, $_SERVER)) + return + $strValue; + }; + + $varReplaceMap = [ + ["SQL", $fncReplaceSQL], + ["Date", $fncReplaceDate], + ["Server", $fncReplaceServer] + ]; + + foreach ($varReplaceMap as $varReplace) + { + $strKey = $varReplace[0]; + $fncReplace = $varReplace[1]; + + preg_match_all( + "/\{\{\s+{$strKey}\:\s+(.+?)\s+\}\}/i", + $strFileData, + $varMatches); + + //if ($varReplace[0] == "Server") + // Respond::json($varMatches); + + for ($i = 0; $i < count($varMatches[0]); $i++) + { + $strMatch = $varMatches[0][$i]; + $strMatchSafe = preg_quote($strMatch); + $strInput = $varMatches[1][$i]; + $strOutput = $fncReplace($strInput); + + while (preg_match("/{$strMatchSafe}/i", $strFileData)) + { $strFileData = preg_replace( "/{$strMatchSafe}/i", - $_SERVER[$strKey], + $strOutput, $strFileData); + } } - catch (Exception $x) {} } + //ob_clean(); + //header("Content-Type: text/plain"); + //echo $strFileData; + //ob_end_flush(); + //exit; + // Get the inputs: preg_match_all( "/declare\s+\@([A-Za-z0-9]{1,})\s+(.+)\s+=\s+\?;(\s+-- ([A-Za-z0-9]{1,})\:\s(.*))?/i", @@ -200,12 +184,12 @@ { try { - $varRows = $c->query($strQueryPath, $varPosted); + $varRows = $c->query($strFileData, $varPosted); $strQueryView = "{$strQueryPath}.php"; if (count($varRows) > 0) { - if (array_key_exists("_section", $varRows[0])) + if (array_key_exists("__Section", $varRows[0])) { $intSectioned = 1; $intSortable = 0; @@ -575,7 +559,7 @@ 0): ?> - +