$params->set Array between square bracket - php

i'm using K2 in Joomla 3.3.
I'm trying to set params (items ids ) to module k2_content from item.php file.
The result must to be between brackets, something like:
["96","68"]
My code is:
$query = "SELECT * FROM #__k2_items WHERE extra_fields_search = '$myautor' AND catid !=1 " ;
$db->setQuery($query);
$losautores = $db->loadObjectList();
$result = array();
foreach ($losautores as $key => $value) {
$result[] = '" '.$value->id.' "';
}
$string_version = implode(',', $result);
$autoresfinal = '['.$string_version.']';
If i test using print, looks ok.
But passing the var to pramas, i get 1064 error.
$params->set('items', $autoresfinal);
To test I tried
$autoresfinal = ["96","68"];
And works fine.
Any idea why doesn't work?
Thank you.

If you assign ["x","y"] you are assigning an array. Here you are transforming the array in a string.
Try simply
$result = [ ];
foreach ($db->loadObjectList() as $key => $value) {
$result[] = $value->id;
}
$params->set('items', $result);
Also, if you wanted to convert the array into a string (possibly JSON), a faster and safer way is to use json_encode (with the appropriate options).
UPDATE
The above remains true, but I had missed your complaint about error 1064. That is a SQL syntax error and it happens before you encode the results.
The reason - as noticed by Fred -ii- - is that in this query, #__k2_items needs escaping with backticks:
$query = "SELECT * FROM #__k2_items WHERE
extra_fields_search = '$myautor' AND catid !=1 " ;
should be:
$query = "SELECT * FROM `#__k2_items` WHERE
extra_fields_search = '$myautor' AND catid !=1 " ;
Also, you probably want to use prepared statements and parameterized queries (find an example here) instead of just plugging $myautor into a string. If you had an author called D'Artagnan, the query would become
....search = 'D'Artagnan' AND ...
which would again fail. Or if I called an author ' OR ''=', the query would become
...search = '' OR ''='' AND ...
which, since '' is always equal to '', would match for all the records in your table.

Related

preg_replace - don't replace in already replaced parts

Given SQL-query with placeholders:
SELECT * FROM table WHERE `a`=? AND `b`=?
and query parameters ['aaa', 'bbb'], i would like to replace ?-placeholders with corresponding params. So, I do it like this:
$sql = preg_replace(array_fill(0, count($params), '#\?#'), $params, $sql, 1);
(we do not concentrate on mysql-escaping, quoting etc. in this question).
Everything works fine and I get
SELECT * FROM table WHERE `a`=aaa AND `b`=bbb
But if our first parameter looks like this: "?aa", everything fails:
SELECT * FROM table WHERE `a`=bbba AND `b`=?
obviously, first replacement pass changes "a=?" into "a=?aa", and second pass changes this (just inserted) question mark into "bbb".
The question is: how can I bypass this confusing preg_replace behaviour?
You can use preg_replace_callback to use one item from $params at a time for each replacement.
$sql = 'SELECT * FROM table WHERE `a`=? AND `b`=?';
var_dump('Original: ' . $sql);
$params=['aaa','bbb'];
$sql = preg_replace_callback("/\\?/",function($m) use (&$params) {
return array_shift($params);
}, $sql);
var_dump('Result: ' . $sql);
Let me know
I would not do this with preg_replace or str_replace. I would use preg_split so empty returns can be removed (If explode had empty removal option I'd use that). For there iterate over the return and add in values. You also can quote the values with this. I presume the purpose of this is for debugging parameterized queries.
$sql = 'SELECT * FROM table WHERE `a`=? AND `b`=?';
$v = array('1?1', "222");
$e = preg_split('/\?/', $sql, NULL, PREG_SPLIT_NO_EMPTY);
$c = '';
foreach($e as $k => $v1){
$c .= $v1 . "'" . $v[$k] ."'";
}
error_log($c);
Then your error log will have:
SELECT * FROM table WHERE `a`='1?1' AND `b`='222'

How do I properly handle a string with an apostrophe when using it within a like clause with PDO?

I am attempting to do a string search with a like clause using PDO. The name has an apostrophe. All my attempts thus far have resulted in no results found even though the names exist.
This code works, where I have hardcoded the array values:
// looking for last names that start with A' and any first name
like_string = array("A'%", "B%");
$sql = "SELECT p.last_name, p.first_name
FROM person p
WHERE p.last_name LIKE ? AND p.first_name LIKE ? ";
$fields = array($like_string[0], $like_string[1]);
$stmt = $this->pdb->prepare($sql);
$stmt->execute($fields);
$result = $stmt->fetchALL(PDO::FETCH_ASSOC);
However this code, where the string array is built within the php code, does not, and I do not understand why.
// e.g $search val = "A', B";
$search_array = explode(',',$search_val);
$like_string[0] = trim($search_array[0]) . "%";
$like_string[1] = trim($search_array[1]) . "%";
The results from the code above produces array values of:
$like_string[0] = "A'%"
$like_string[1] = "B%"
yet no rows are returned. I have even tried adding addslashes as seen below - still no rows fetched:
// e.g $search val = "A', B";
$search_array = explode(',',$search_val);
$like_string[0] = addslashes(trim($search_array[0]) . "%");
$like_string[1] = addslashes(trim($search_array[1]) . "%");
Any help would be greatly appreciated.
As an update to a previous comment, the code below produces
$search_val = "A', B";
$search_array = explode(',',$search_val);
$like_string[0] = trim($search_array[0]) . "%";
$like_string[1] = trim($search_array[1]) . "%";
var_dump($like_string);
the following output from var_dump
array (size=2)
0 => string 'A'%' (length=3)
1 => string 'B%' (length=2)
And I believe the issue is that the resultant strings above are not surrounded in double quotes. So how do I force that to occur?
I discovered the issue. The search string entered by the user was being sanitized by calling
escape_string(filter_var($item_to_prep, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH));
This caused a conflict with the PDO functions.

Matching Comma Separated mysql tags to database values (WP - PHP)

$tagList = get_the_tag_list('','---','');
$totaltags = explode('---',$tagList);
foreach ($alltags AS $eachtag)
{
$thistag = GetBetween($eachtag,'/tag/','/');
$SQL = "SELECT * FROM table WHERE thetag = '$eachtag'"
$result = mysql_query($SQL, $link) or die(mysql_error());
if(mysql_affected_rows()>0)
{
echo $thistag;
}
}
This is my working code. It works, but I really don't like having the SQL command in the foreach. I assumed it wouldn't be an issue since there's no more than 8 tags on any given page. Is there a more efficient way to code this? (i.e. optimize for 1 mysql command or have less code)
This is my working code. It works, but I really don't like having the SQL command in the foreach. I assumed it wouldn't be an issue since there's no more than 8 tags on any given page. Is there a more efficient way to code this? (i.e. optimize for 1 mysql command or have less code)
Quite simple really:
<?php
// build quotes around the tags, this specific syntax is PHP 5.3+
$alltags = array_map( $alltags, function( $value ) {
return "'" . mysql_real_escape_string( $value ) . "'";
});
$query = 'SELECT * FROM table WHERE thetag IN ( %s );';
$sql = sprintf( $query, implode( ', ', $alltags ) );
echo $sql;
Take a look at the FIND_IN_SET function.

MySQL where clause equals anything (SELECT * WHERE col = ANY_VALUE)

I'd like to create a query in MySQL that has an optional value. When the value is specified the query is filtered by that value, when the value is not all rows are returned. Here's the idea:
public function doQuery($item = 'ANY_VALUE') {
$query = "SELECT * FROM table WHERE item = ?";
db->fetchAll($query,array($item))
...
}
doQuery(); // Returns everything
doQuery($item='item1'); // Returns only rows where item = 'item1'
Is there an easy way to do this without creating two query strings depending on the value of $item?
As far as I know, no such "any" placeholder exists.
If you can use LIKE, you could do
SELECT * FROM table WHERE item LIKE '%'
if you can append a condition, you could nullify the item clause like this:
SELECT * FROM table WHERE item = ? OR 1=1
(won't work in your example though, because you are passing "item" as a parameter)
That's all the options I can see - it's probably easiest to work with two queries, removing the WHERE clause altogether in the second one.
This would probably work, but I*m not sure whether it's a good idea from a database point of view.
public function doQuery($item = 'ANY_VALUE') {
$query = "SELECT * FROM table WHERE item = ? OR 1 = ?";
db->fetchAll($query,array($item, ($item == 'ANY_VALUE' ? 1 : 0))
...
}
Better way to do this is first generate sql query from the parameter you need to bother on, and then execute.
function doQuery($params) {
$query = 'SELECT * FROM mytable ';
if (is_array($params) // or whatever your condition ) {
$query .= 'WHERE item = ' . $params[0];
}
$query .= ' ;';
// execute generated query
execute($query);
}
You cannot get distinct results without giving distinct query strings.
Using $q = "... WHERE item = '$item'" you DO create distinct query strings depending on the value of $item, so it is not that different from using
$q = "..." . ($item=='ANY_VALUE' ? something : s_th_else);.
That said I see two or three options:
use function doQuery($item = "%") { $query = "SELECT ... WHERE item LIKE '$item'"; ...}
But then callers to that function must know that they must escape a '%' or '_' character properly if they want to search for an item having this character literally (e.g. for item = "5% alcoholic solution", giving this as argument would also find "50-50 sunflower and olive oil non alcoholic solution".
use function doQuery($item = NULL) { $query = "SELECT ..."; if ($item !== NULL) $query .= " WHERE item = '$item' "; ...} (where I use NULL to allow any other string or numerical value as a valid "non-empty" argument; in case you also want to allow to search for NULL (without quotes) you must choose another "impossible" default value, e.g., [], and you must anyway use a distinct query without the single quotes which however are very important in the general case), or even:
use function doQuery($item = NULL) { if($item === NULL) $query = "SELECT ..."; else $query = "SELECT ... WHERE item = '$item' "; ...}, which is more to type but probably faster since it will avoid an additional string manipulation (concatenation of the first and second part).
I think the 2nd & 3rd options are better than the first one. You should explain why you want to avoid these better solutions.
PS: always take care of not forgetting the quotes in the SQL, and even to properly escape any special characters (quotes, ...) in arguments which can depend on user input, as to avoid SQL injections. You may be keen on finding shortest possible solutions (as I am), but neglecting such aspects is a no-no: it's not a valid solution, so it's not the shortest solution!

How to get "field names" using PHP ADOdb?

I'm using PHP ADOdb and I can get the result set:
$result = &$db->Execute($query);
How do I get the field names from that one row and loop through it?
(I'm using access database if that matters.)
It will depend on your fetch mode - if you setFetchMode to ADODB_FETCH_NUM (probably the default) each row contains a flat array of columns. If you setFetchMode to ADODB_FETCH_ASSOC you get an associative array where you can access each value by a key. The following is taken from ADODB documentation - http://phplens.com/lens/adodb/docs-adodb.htm#ex1
$db->SetFetchMode(ADODB_FETCH_NUM);
$rs1 = $db->Execute('select * from table');
$db->SetFetchMode(ADODB_FETCH_ASSOC);
$rs2 = $db->Execute('select * from table');
print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
To loop through a set of results:
$result = &$db->Execute($query);
foreach ($result as $row) {
print_r($row);
}
Small improvement to the solution posted by #thetaiko.
If you are ONLY needing the field names, append LIMIT 1 to the end of your select statement (as shown below). This will tell the server to send you a single row with column names, rather than sending you the entire table.
SELECT * FROM table LIMIT 1;
I'm working with a table that contains 9.1M records, so this minor change speeds up the query significantly!
This is a function I use to return a field array - I've stripped out some extra stuff that, for example, allows it to work with other DBs than MySQL.
function getFieldNames($strTable, $cn) {
$aRet = array();
# Get Field Names:
$lngCountFields = 0;
$strSQL = "SELECT * FROM $strTable LIMIT 1;";
$rs = $cn->Execute($strSQL)
or die("Error in query: \n$strSQL\n" . $cn->ErrorMsg());
if (!$rs->EOF) {
for ($i = 0; $i < $rs->FieldCount(); $i++) {
$fld = $rs->FetchField($i);
$aRet[$lngCountFields] = $fld->name;
$lngCountFields++;
}
}
$rs->Close();
$rs = null;
return $aRet;
}
Edit: just to point out that, as I say, I've stripped out some extra stuff, and the EOF check is therefore no longer necessary in the above, reduced version.
I initally tried to use MetaColumnNames, but it gave differing results in VisualPHPUnit and actual site, while running from the same server, so eventually
I ended up doing something like this:
$sql = "select column_name, column_key, column_default, data_type, table_name, table_schema from information_schema.columns";
$sql .= ' where table_name="'.$table.'" and table_schema="'.$database_name.'"';
$result = $conn->Execute($sql);
while($row = $result->fetchRow()) {
$out[] = strToUpper($row['column_name']);
}
I think it should work with mysql, mssql and postgres.
The benefit of doing it like this, is that you can get the column names, even if a query from a table returns an empty set.
If you need the Coloumn names even for empty tables or for joins about multiple tables use this:
$db->Execute("SELECT .......");
// FieldTypesArray - Reads ColoumnInfo from Result, even for Joins
$colInfo = $res->FieldTypesArray();
$colNames = array();
foreach($colInfo as $info) $colNames[] = $info->name;
The OP is asking for a list of fieldnames that would result of executing an sql statement stored in $query.
Using $result->fetchRow(), even with fetch mode set to associative, will return nothing if no records match the criteria set by $query. The $result->fields array would also be empty and would give no information for getting the fieldnames list.
Actually, we don't know what's inside the $query statement. Besides, setting limit to 1 may not compatible with all database drivers supported by PHP ADOdb.
Answer by Radon8472 is the right one, but the correct code could be:
$result = $db->Execute($query);
// FieldTypesArray - an array of ADOFieldObject Objects
// read from $result, even for empty sets or when
// using * as field list.
$colInfo = [];
if (is_subclass_of($result, 'ADORecordSet')){
foreach ($result->FieldTypesArray() as $info) {
$colInfo[] = $info->name;
}
}
I have the habit of checking the class name of $result, for as PHP ADOdb will return false if execution fails.

Categories