I am getting my feet wet with Kohana but having trouble with pagination. i get the following error :
ErrorException [ Fatal Error ]: Class
'Pagination' not found
following the unoffical wiki I amended the bootstrap file to include this:
Kohana::modules(array( 'database' => MODPATH.'database', 'userguide' => MODPATH.'userguide', 'pagination' => MODPATH.'pagination', ))
but that didn't seem to help.
my second question is with regards to query count.... I am surprised there is no function like $query-count() unless i opt for ORM instead i find this solution a bit clunky given that a query count is a must for every pagination request:
$result['count'] = $pagination_query->select('COUNT("*") AS result_count')->execute()->get('result_count');
Any suggestions?
thank you very much
Kohana 3.1 does not come with the pagination module...
it must be downloaded from
https://github.com/kohana/pagination
then go to the class/kohana edit line 199 from ->uri to ->uri()
that does it
as to the query count....still searching.
hope this helps someone
There used to be a count_last_query() function in the Database class which provided the total results of the last query run as it would be without any limit or offset, but they pulled it from version 3.0.9. You can find the documentation of it here:
http://kohanaframework.org/3.0/guide/api/Database#count_last_query
I've actually built upon the code from that function to make my own count query function if you want to use that.
protected static function _pagedQuery($query) {
$sql = (string)$query;
if (stripos($sql, 'LIMIT') !== FALSE) {
// Remove LIMIT from the SQL
$sql = preg_replace('/\sLIMIT\s+[^a-z]+/i', ' ', $sql);
}
if (stripos($sql, 'OFFSET') !== FALSE) {
// Remove OFFSET from the SQL
$sql = preg_replace('/\sOFFSET\s+\d+/i', '', $sql);
}
if (stripos($sql, 'ORDER BY') !== FALSE) {
// Remove ORDER BY from the SQL
$sql = preg_replace('/\sORDER BY\s+`\w+`(\.`\w+`)?(\s+DESC|\s+ASC)?/i', '', $sql);
}
$db = Database::instance();
$result = $db->query(Database::SELECT, '
SELECT COUNT(*) AS ' . $db->quote_identifier('total_rows') . '
FROM (' . $sql . ') AS ' . $db->quote_table('counted_results'),
TRUE
);
return (int)$result->current()->total_rows;
}
Related
I'm looking for a way to dynamically build a SQL query for an unknown number of API parameters that may come back. As a simple example, consider the following query:
router.get("/someEndpoint", authorizationFunction, async (req, res) => {
let sql = `
SELECT *
FROM some_table
WHERE username = $1
${req.query.since !== undefined ? "AND hire_date >= $2" : ""}
`
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
where pool is defined as
const Pool = require("pg").Pool;
const pool = new Pool({<connection parameters>});
The problem I'm having is that if req.query.since is not provided, then the SQL query only requires a single bound parameter ($1). This is presented as an error that says bind message supplies 2 parameters, but prepared statement "" requires 1. Since I don't know which parameters a user will provide until the time of the query, I'm under the impression that I need to provide all possible value, and let the query figure it out.
I've seen a lot of posts that point to pg-promise as a solution, but I'm wondering if that's necessary. Is there a way that I can solve this with my current setup? Perhaps I'm thinking about the problem incorrectly?
Thanks in advance!
Add a trivial expression text that contains $2 and evaluates to true instead of "", for example
SELECT * FROM some_table WHERE username = $1 AND
${req.query.since !== undefined ? " hire_date >= $2": " (true or $2 = $2)"}
The planner will remove it anyway. Added true or just in case $2 is null.
Still it would be cleaner like this
if (req.query.since !== undefined)
{
let sql = `SELECT * FROM some_table WHERE username = $1 AND hire_date >= $2`;
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
else
{
let sql = `SELECT * FROM some_table WHERE username = $1`;
const results = await pool.query(sql, [req.query.user]);
}
What about SQLi risk BTW?
I'm using the node-sqlite3 package to access my db.
I'm trying to get rows from a Clients table with this code:
var st = db.prepare("SELECT * FROM Clients where name LIKE '%$name%'");
st.all({ $name: "test" }, function (err, rows) {
console.log("this: " + JSON.stringify(this));
if (err)
console.log(err);
else {
console.log("found: " + JSON.stringify(rows));
}
});
Output of err is this:
{ [Error: SQLITE_RANGE: bind or column index out of range] errno: 25, code: 'SQLITE_RANGE' }
The query works and doesn't throw errors when I change the sql to SELECT * FROM Clients where name LIKE '%$name%'. So I guess the problem is, that node-sqlite3 tries to find a variable called $name% or something like that in the object passed as first parameter to Statement#all.
I've searched the API doc for more hints about this, but couldn't find any.
Do I need to escape something? How do I get my query to work with named binding and the sql wildcards %?
This is not the way bindings work.
You can have
SELECT * FROM Clients where name LIKE $name
and
var name = "%"+"test"+"%";
..
{ $name: name }
bound variables are negociated with the backend database as a "whole" variable and you should not confuse this with variable replacement.
you should also be able to use the concatenate function of sqlite (not tested) :
SELECT * FROM Clients where name LIKE '%'||$name||'%'
..
{ $name: test }
Consider the following Silverstripe page class
<?php
class Page extends SiteTree{
static $has_many = array('OtherDataObjects' => 'DataObjectClass');
public function getSearchContext() {
$fields = new FieldSet(
new TextField('Title', 'Tour'),
new DropdownField('OtherDataObjects', 'Other Data Object', array('data', 'value')
);
$filters = array(
'Title' => new PartialMatchFilter('Title'),
'OtherDataObjects' => new PartialMatchFilter('OtherDataObjects.Title')
);
return new SearchContext(
'Page',
$fields,
$filters
);
}
}
Adding this search form to a front-end form and posting a search form always results in a [User Error] with a SQL error containing something like this at the end.
AND ("DataObjectClass_Live"."DataObjectClass_Live" LIKE 'title') ORDER BY "Sort" LIMIT 25 OFFSET 0 Table 'database DataObjectClass_Live' doesn't exist
My searchcontext search throws up an error each time I try to run a search on a has_many relationship. The versioned extension seems to be the culprit because it adds _live to all tables regardless whether the baseclass has the versioned extension or not I get the same error in SilverStripe versions 2.4.x and the latest 3.0.x versions.
Any help or pointers will be appreciated.
maybe try using an sqlQuery. something like
function SearchResults() {
$select = array('*');
$from = array('OtherDataObjects');
$where = array('OtherDataObjects:PartialMatch' => '%' . $data['Title'] . '%');
$sqlQuery = new SQLQuery($select, $from, $where);
$results = $sqlQuery->execute();
return $results;
}
$data['Title'] is to be the value from the search textbox
partial match reference: http://doc.silverstripe.org/framework/en/topics/datamodel
sql query reference: http://doc.silverstripe.org/framework/en/reference/sqlquery
When i scanned my site with "Acunetix Web Vulnerability Scanner" i was very surprised. Programm show a lot of xss vulnerabilities on page when i use get parameters with xss filtration.
For example:
URL encoded GET input state was set to " onmouseover=prompt(967567) bad="
The input is reflected inside a tag parameter between double quotes.
I think its because i don`t show 404 error when result is empty (it should be). I show message like "the request is empty"
My controller:
$this->pagination->initialize($config);
$this->load->model('aircraft_model');
$data['type'] = $this->input->get('type', TRUE);
$data['year'] = $this->input->get('year', TRUE);
$data['state'] = $this->input->get('state', TRUE);
$type_param = array (
'type' => $this->input->get('type', TRUE),
);
$parameters = array(
'year' => $this->input->get('year', TRUE),
'state_id' => $this->input->get('state', TRUE),
);
foreach ($parameters as $key=>$val)
{
if(!$parameters[$key])
{
unset($parameters[$key]);
}
}
$data['aircraft'] = $this->aircraft_model->get_aircraft($config['per_page'], $this->uri->segment(3, 1),$parameters, $type_param);
$data['title'] = 'Самолеты | ';
$data['error'] = '';
if (empty($data['aircraft']))
{
$data['error'] = '<br /><div class="alert alert-info"><b>По таким критериям не найдено ниодного самолета</b></div>';
}
$name = 'aircraft';
$this->template->index_view($data, $name);
even when i turn on global xss filtering program find xss vulnerabilities.
Maybe Message for possible xss is false?
Also i have one SQL injection.
Attack details:
Path Fragment input / was set to \
Error message found:
You have an error in your SQL syntax
SQL error:
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-10, 10' at line 3
SELECT * FROM (`db_cyclopedia`) LIMIT -10, 10
Controller:
$this->load->model('cyclopedia_model');
$this->load->library('pagination');
$config['use_page_numbers'] = TRUE;
[pagination config]
$config['suffix'] = '/?'.http_build_query(array('type' => $this->input->get('type', TRUE)), '', "&");
$config['base_url'] = base_url().'cyclopedia/page/';
$count_all = $this->cyclopedia_model->count_all($this->input->get('type', TRUE));
if (!empty($count_all)){
$config['total_rows'] = $count_all;
}
else
{
$config['total_rows'] = $this->db->count_all('cyclopedia');
}
$config['per_page'] = 10;
$config['first_url'] = base_url().'cyclopedia/page/1'.'/?'.http_build_query(array('type' => $this->input->get('type', TRUE)), '', "&");
$this->pagination->initialize($config);
$parameters = array(
'cyclopedia_cat_id' => $this->input->get('type', TRUE),
);
foreach ($parameters as $key=>$val)
{
if(!$parameters[$key])
{
unset($parameters[$key]);
}
}
$data['type'] = $this->input->get('type', TRUE);
$data['cyclopedia'] = $this->cyclopedia_model->get_cyclopedia($config['per_page'], $this->uri->segment(3, 1),$parameters);
$data['title'] = 'Энциклопедия | ';
if (empty($data['cyclopedia']))
{
show_404();
}
$name = 'cyclopedia';
$this->template->index_view($data, $name);
And one some problems with HTTP Parameter Pollution (get parameters).
Attack details
URL encoded GET input state was set to &n954725=v953060
Parameter precedence: last occurrence
Affected link: /aircraft/grid/?type=&year=&state=&n954725=v953060
Affected parameter: type=
Sorry for a lot of code, but its my first experience with codeigniter / framework and safety first.
UPDATE:
When site url like this site.com/1 codeigniter show:
An Error Was Encountered
Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.
how to make a show 404 instead of this message?
This takes input from the user:
$config['first_url'] = base_url().'cyclopedia/page/1'.'/?'.http_build_query(array('type' => $this->input->get('type', TRUE)), '', "&");
Then this line in the Pagination.php library spits it into the output page without proper HTML-escaping:
$output .= $this->first_tag_open.'<a '.$this->anchor_class.'href="'.$first_url.'">'.$this->first_link.'</a>'.$this->first_tag_close;
Although automated scanning tools do generate a lot of false positives in general, this one is a genuine HTML-injection vulnerability leading to a real risk of cross-site scripting attacks.
To fix, wrap all output being injected into HTML context (eg $first_url) with htmlspecialchars(). Unfortunately as this is library code you would have to start your own fork of Pagination. Might be better to use some other library.
Don't rely on xss_clean as it can't reliably protect you. It is attempting to deal with output problems at the input layer, which is never going to work right - it'll miss attacks as well as mangling perfectly valid input. The whole idea betrays a basic, rookie misunderstanding of what the XSS problem actually is.
There are more places in Pagination that need the same fix, but I don't want to spend any more time reading CodeIgniter's painfully poor-quality code than I have to.
I do not understand how CodeIgniter has attained this degree of popularity.
In my module I have this implementation where I have a hook_search_execute() function which can be used for rewriting/extending default Drupal search. This function calls for executeFirstPass() method and adds to the query the following $first->addExpression('SUM(i.score * t.count)', 'calculated_score');
When I'm trying to add my sorting as following $query->orderBy('calculated_score', 'ASC');, I have an error.
However if I add $query->orderBy('n.title', 'ASC'); or $query->orderBy('n.created', 'ASC'); everything is fine and is sorting as it should be.
Does anyone have any ideas why this is happens?
After all my research I came only to this crappy solution.
In modules/search/search.extender.inc file we have the following code in line 437 (depends on Drupal version).
....
// Convert scores to an expression.
$this->addExpression('SUM(' . implode(' + ', $this->scores) . ')', 'calculated_score', $this->scoresArguments);
if (count($this->getOrderBy()) == 0) {
// Add default order after adding the expression.
$this->orderBy('calculated_score', 'DESC');
}
....
I turned this code into:
....
// Convert scores to an expression.
$this->addExpression('SUM(' . implode(' + ', $this->scores) . ')', 'calculated_score', $this->scoresArguments);
if (count($this->getOrderBy()) == 0) {
if ($_GET['orderby'] == 'relevance' && $_GET['orderdir'] == 'ASC') {
$dir = 'ASC';
}
else {
$dir = 'DESC';
}
// Add default order after adding the expression.
$this->orderBy('calculated_score', $dir);
}
....
Please feel free to propose clean solution.