Skip to content

Commit

Permalink
Merge pull request #42 from bakaphp/0.1-sort-injection
Browse files Browse the repository at this point in the history
  • Loading branch information
kaioken authored Apr 26, 2021
2 parents 1140f89 + 97118bb commit 5ea7d96
Showing 1 changed file with 65 additions and 68 deletions.
133 changes: 65 additions & 68 deletions src/QueryParserCustomFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Exception;

/**
* Base QueryParser. Parse GET request for a API to a array Phalcon Model find and FindFirst can intepret
* Base QueryParser. Parse GET request for a API to a array Phalcon Model find and FindFirst can intepret.
*
* Supports queries with the following paramters:
* Searching:
Expand Down Expand Up @@ -91,7 +91,7 @@ class QueryParserCustomFields extends QueryParser
private $bindParamsValues = [];

/**
* Pass the request
* Pass the request.
*/
public function __construct(array $request, Model $model)
{
Expand All @@ -105,9 +105,10 @@ public function __construct(array $request, Model $model)
* Sets Controller fields for these variables.
*
* @param array $allowedFields Allowed fields array for search and partials
* @return boolean Always true if no exception is thrown
*
* @return bool Always true if no exception is thrown
*/
public function request(): array
public function request() : array
{
$params = [
'subquery' => '',
Expand Down Expand Up @@ -171,48 +172,25 @@ public function request(): array

if (!empty($sort)) {
// Get the model, column and sort order from the sent parameter.
list($modelColumn, $order) = explode('|', $sort);
// Check to see whether this is a related sorting by looking for a .
if (strpos($modelColumn, '.') !== false) {
// We are using a related sort.
// Get the namespace for the models from the configuration.
$modelNamespace = \Phalcon\Di::getDefault()->getConfig()->namespace->models;
// Get the model name and the sort column from the sent parameter
list($model, $column) = explode('.', $modelColumn);
// Convert the model name into camel case.
$modelName = str_replace(' ', '', ucwords(str_replace('_', ' ', $model)));
// Create the model name with the appended namespace.
$modelName = $modelNamespace . '\\' . $modelName;

// Make sure the model exists.
if (!class_exists($modelName)) {
throw new \Exception('Related model does not exist.');
}
$modelColumn = $sort;
if (strpos($sort, '|') !== false) {
list($modelColumn, $order) = explode('|', $sort);
}
$order = strtolower($order) === 'asc' ? 'ASC' : 'DESC';

// Instance the model so we have access to the getSource() function.
$modelObject = new $modelName();
// Instance meta data memory to access the primary keys for the table.
$metaData = new \Phalcon\Mvc\Model\MetaData\Memory();
// Get the first matching primary key.
// @TODO This will hurt on compound primary keys.
$primaryKey = $metaData->getPrimaryKeyAttributes($modelObject)[0];
// We need the table to exist in the query in order for the related sort to work.
// Therefore we add it to comply with this by comparing the primary key to not being NULL.
$this->relationSearchFields[$modelName][] = [
$primaryKey, ':', '$$',
];

$sort = " ORDER BY {$modelObject->getSource()}.{$column} {$order}";
unset($modelObject);
} else {
$modelColumn = preg_replace("/[^a-zA-Z0-9_\s]/", '', $modelColumn);
$columnsData = $this->getTableColumns();
if (isset($columnsData[$modelColumn])) {
$sort = " ORDER BY {$modelColumn} {$order}";
} else {
$sort = '';
}
}
}

// Append any additional user parameters
$this->appendAdditionalParams();
//base on th eesarch params get the raw query
//base on the search params get the raw query
$rawSql = $this->prepareCustomSearch();

//sort
Expand All @@ -228,12 +206,13 @@ public function request(): array
}

/**
* gien the request array , get the custom query to find the results
* gien the request array , get the custom query to find the results.
*
* @param array $params
*
* @return string
*/
protected function prepareCustomSearch($hasSubquery = false): array
protected function prepareCustomSearch($hasSubquery = false) : array
{
$metaData = new \Phalcon\Mvc\Model\MetaData\Memory();
$classReflection = (new \ReflectionClass($this->model));
Expand Down Expand Up @@ -261,10 +240,10 @@ protected function prepareCustomSearch($hasSubquery = false): array

$relationKey = $primaryKey;
$referenceKey = $primaryKey;

if (isset($relation) && $relation && count($relation)) {
$relationKey = $relation[0]->getFields();
$referenceKey = $relation[0]->getReferencedFields();
$relationKey = $relation[0]->getFields();
$referenceKey = $relation[0]->getReferencedFields();
}

$sql .= " INNER JOIN {$model} ON {$model}.{$relatedKey} = (";
Expand Down Expand Up @@ -360,7 +339,7 @@ protected function prepareCustomSearch($hasSubquery = false): array
*
* @return string
*/
private function prepareNormalSql(array $searchCriteria, string $classname, string $andOr, int $fKey): string
private function prepareNormalSql(array $searchCriteria, string $classname, string $andOr, int $fKey) : string
{
$sql = '';
$textFields = $this->getTextFields($classname);
Expand Down Expand Up @@ -402,7 +381,7 @@ private function prepareNormalSql(array $searchCriteria, string $classname, stri
}

if ($value == 'null') {
$logicConector = !$vKey ? " " . $andOr .' (' : ' OR ';
$logicConector = !$vKey ? ' ' . $andOr . ' (' : ' OR ';
$sql .= $logicConector . $classname . '.' . $searchField . ' IS NULL';
} else {
if (!$vKey) {
Expand Down Expand Up @@ -433,7 +412,7 @@ private function prepareNormalSql(array $searchCriteria, string $classname, stri
*
* @return string
*/
private function prepareRelatedSql(array $searchCriteria, string $classname, string $andOr, int $fKey): string
private function prepareRelatedSql(array $searchCriteria, string $classname, string $andOr, int $fKey) : string
{
$sql = '';
$textFields = $this->getTextFields($classname);
Expand Down Expand Up @@ -501,7 +480,7 @@ private function prepareRelatedSql(array $searchCriteria, string $classname, str
*
* @return string
*/
private function prepareCustomSql(array $searchCriteria, Model $modules, string $classname, string $andOr, int $fKey): string
private function prepareCustomSql(array $searchCriteria, Model $modules, string $classname, string $andOr, int $fKey) : string
{
$sql = '';
list($searchField, $operator, $searchValue) = $searchCriteria;
Expand Down Expand Up @@ -557,25 +536,25 @@ private function prepareCustomSql(array $searchCriteria, Model $modules, string
}

/**
* Preparse the parameters to be used in the search
* Preparse the parameters to be used in the search.
*
* @return void
*/
protected function prepareParams(array $unparsed): void
protected function prepareParams(array $unparsed) : void
{
$this->relationSearchFields = array_key_exists('rparams', $unparsed) ? $this->parseRelationParameters($unparsed['rparams']) : [];
$this->customSearchFields = array_key_exists('cparams', $unparsed) ? $this->parseSearchParameters($unparsed['cparams'])['mapped'] : [];
$this->normalSearchFields = array_key_exists('params', $unparsed) ? $this->parseSearchParameters($unparsed['params'])['mapped'] : [];
}

/**
* Parse relationship query parameters
* Parse relationship query parameters.
*
* @param array $unparsed
*
* @return array
*/
protected function parseRelationParameters(array $unparsed): array
protected function parseRelationParameters(array $unparsed) : array
{
$parseRelationParameters = [];
$modelNamespace = \Phalcon\Di::getDefault()->getConfig()->namespace->models;
Expand All @@ -599,12 +578,13 @@ protected function parseRelationParameters(array $unparsed): array
* Unparsed, they will look like this:
* (name:Benjamin Framklin,location:Philadelphia)
* Parsed:
* array('name'=>'Benjamin Franklin', 'location'=>'Philadelphia')
* array('name'=>'Benjamin Franklin', 'location'=>'Philadelphia').
*
* @param string $unparsed Unparsed search string
*
* @return array An array of fieldname=>value search parameters
*/
public function parseSearchParameters(string $unparsed): array
public function parseSearchParameters(string $unparsed) : array
{
// $unparsed = urldecode($unparsed);
// Strip parens that come with the request string
Expand Down Expand Up @@ -645,12 +625,13 @@ public function parseSearchParameters(string $unparsed): array

/**
* get the text field from this model database
* so we can do like search
* so we can do like search.
*
* @param string $table
*
* @return array
*/
private function getTextFields($table): array
private function getTextFields($table) : array
{
$columnsData = $this->model->getReadConnection()->describeColumns($table);
$textFields = [];
Expand All @@ -668,11 +649,11 @@ private function getTextFields($table): array
}

/**
* Append any defined additional parameters
* Append any defined additional parameters.
*
* @return void
*/
public function appendAdditionalParams(): void
public function appendAdditionalParams() : void
{
if (!empty($this->additionalSearchFields)) {
$this->normalSearchFields = array_merge_recursive($this->normalSearchFields, $this->additionalSearchFields);
Expand All @@ -688,37 +669,37 @@ public function appendAdditionalParams(): void
}

/**
* Append additional search parameters
* Append additional search parameters.
*
* @param array $params
*
* @return void
*/
public function appendParams(array $params): void
public function appendParams(array $params) : void
{
$this->additionalSearchFields = $params;
}

/**
* Append additional search parameters
* Append additional search parameters.
*
* @param array $params
*
* @return void
*/
public function appendCustomParams(array $params): void
public function appendCustomParams(array $params) : void
{
$this->additionalCustomSearchFields = $params;
}

/**
* Append additional search parameters
* Append additional search parameters.
*
* @param array $params
*
* @return void
*/
public function appendRelationParams(array $params): void
public function appendRelationParams(array $params) : void
{
$this->additionalRelationSearchFields = $params;
}
Expand All @@ -730,7 +711,7 @@ public function appendRelationParams(array $params): void
*
* @return void
*/
protected function parseColumns(string $columns): void
protected function parseColumns(string $columns) : void
{
// Split the columns string into individual columns
$columns = explode(',', $columns);
Expand All @@ -752,7 +733,7 @@ protected function parseColumns(string $columns): void
*
* @return int
*/
public function getLimit(): int
public function getLimit() : int
{
return $this->limit;
}
Expand All @@ -762,7 +743,7 @@ public function getLimit(): int
*
* @return int
*/
public function getPage(): int
public function getPage() : int
{
return $this->page;
}
Expand All @@ -772,16 +753,17 @@ public function getPage(): int
*
* @return int
*/
public function getOffset(): int
public function getOffset() : int
{
return $this->offset;
}

/**
* Based on the given relaitonship , add the relation array to the Resultset
* Based on the given relationship , add the relation array to the Resultset.
*
* @param string $relationships
* @param Model $results
*
* @return array
*/
public static function parseRelationShips(string $relationships, &$results) : array
Expand All @@ -804,4 +786,19 @@ public static function parseRelationShips(string $relationships, &$results) : ar
unset($results);
return $newResults;
}

/**
* Get table columns.
*/
public function getTableColumns() : array
{
$fields = $this->model->getReadConnection()->describeColumns($this->model->getSource());
$columns = [];

foreach ($fields as $field) {
$columns[$field->getName()] = $field->getName();
}

return $columns;
}
}

0 comments on commit 5ea7d96

Please sign in to comment.