PHP Error: Cannot use a scalar value as an array... However - php

I'm currently working with the medoo.php framework, and although I would normally use their ticket area on github, it appears that no one actually uses that... so...
At any rate, when I'm running one of my files which uses "require" to call the framework, I get the following error:
Warning: Cannot use a scalar value as an array in /home/..../public_html/projects/friendcodes/medoo.min.php on line 759
However, when I inspect the code (the below is lines 752 to 764), I see that it is in fact supposed to check if $where is not set, and if it isn't, make it an array - however this php error begs to differ.
I'm guessing that $where is being set as a variable somewhere else, that's not an array, but there are over 100 occurrences of the variable in the framework, and 830 lines of code, which you probably don't want to see. (Let me know in a comment and I'll add it - again, this is directly from medoo's most two recent updates/releases.)
public function get($table, $columns, $where = null)
{
if (!isset($where))
{
$where = array();
}
$where['LIMIT'] = 1;
$data = $this->select($table, $columns, $where);
return isset($data[0]) ? $data[0] : false;
}
My main question is - How do I rectify this problem without breaking something in this framework which is extremely complex (for my level, at any rate)
Update: How silly of me! I found the problem. Just as people suggested, I was calling $where wrong.
I was calling it with:
$accountinfo = $database->get('xf_user_field_value', ['field_value'], 1);
Instead of
$accountinfo = $database->get('xf_user_field_value', ['field_value'], ["user_id"=>1]);
(Where the third arg is $where) Thanks for the help guys!

Right, first things first, we need to find out what is calling get that shouldn't be. WHICH IS THE ENTIRE PROBLEM. The problem isn't the function itself, the problem is something is calling it using an argument for $where which isn't an array. Changing a library to fix one faulty call is ridiculous.
Step 1: Temporarily edit the get function to include a print_r of the $where variable.
public function get($table, $columns, $where = null)
{
if(isset($where)) print_r($where);
if (!isset($where))
{
$where = array();
}
$where['LIMIT'] = 1;
$data = $this->select($table, $columns, $where);
return isset($data[0]) ? $data[0] : false;
}
This will show us before the error prints the value of $where, which will help you find the malformed get call.
If this fails, try using PHP's built-in backtrace to try to find the issue:
public function get($table, $columns, $where = null)
{
if(isset($where)) print_r(debug_backtrace());
if (!isset($where))
{
$where = array();
}
$where['LIMIT'] = 1;
$data = $this->select($table, $columns, $where);
return isset($data[0]) ? $data[0] : false;
}

The ->get() method is not called properly.
Cannot use a scalar value as an array
That warning is shown if $where is either true, a numeric value or a resource. Valid method calls include:
->get('table', '*')
->get('table', '*', array('WHERE' => 'foo = "bar"'))
Check the manual and fix your code.

EDIT 3: try moving $where['LIMIT'] = 1; inside of the isset statement, since you wouldn't want to pass LIMIT 1 to the query constructor if $where is passed by reference.
DISCLAIMER I have no knowledge of the medoo framework.
public function get($table, $columns, $where = null)
{
if (is_null($where))
{
$where = array('LIMIT'=>1);
}
$data = $this->select($table, $columns, $where);
return isset($data[0]) ? $data[0] : false;
}

Related

Reference- what is wrong with my codeigniter code

hello everyone i write a codeigniter function to return data fro database
this is my function
public function get_total_results($filtering = false)
{
if ($filtering) {
$this->get_filtering();
}
foreach ($this->joins as $val) {
$this->ci->db->join($val[0], $val[1], $val[2]);
}
foreach ($this->where as $val) {
$this->ci->db->where($val[0], $val[1], $val[2]);
}
foreach ($this->or_where as $val) {
$this->ci->db->or_where($val[0], $val[1], $val[2]);
}
foreach ($this->group_by as $val) {
$this->ci->db->group_by($val);
}
foreach ($this->like as $val) {
$this->ci->db->like($val[0], $val[1], $val[2]);
}
if (strlen($this->distinct) > 0) {
$this->ci->db->distinct($this->distinct);
$this->ci->db->select($this->columns);
}
$query = $this->ci->db->get($this->table, null, null, false);
return $query->num_rows();
}
but i get an error of
An uncaught Exception was encountered
Type: Error
Message: Call to a member function num_rows() on boolean
in line of return $query->num_rows();
i don't know what is wrong with my code that i got this error so i know the error in last line in returning result any suggestion or idea
The problem is that the line
$query = $this->ci->db->get($this->table, null, null, false);
// Note: all you really need is $this->ci->db->get($this->table);
It is assigning the value false to $query. That usually happens when Query Builder creates a SQL statement that does not make sense - it happens.
You can see what Query Builder creates this way
// comment out the get() call
// $this->ci->db->get($this->table);
// run this instead
$sql = $this->db->get_compiled_select($this->table);
echo $sql;
// remove the comments once you see where the problem is
//return $query->num_rows();
You will probably be able to see where the SQL statement syntax is wrong and adjust your earlier code accordingly.
You might want to add a check of the get() return to your logic, e.g.
$query = $this->ci->db->get($this->table);
// Is $query truthy? (not false, null, etc)
if(! empty($query))
{
return $query->num_rows();
}
get() method of codeigniter have syntax like:
get([$table = ''[, $limit = NULL[, $offset = NULL]]])
Parameters: $table (string) – The table to query $limit (int) – The
LIMIT clause $offset (int) – The OFFSET clause
Returns: CI_DB_result instance (method chaining)
Return type: CI_DB_result
You have passed more than three parameters. So, Please check the parameters. It may resolve your problem.
Refer this for more information.

Dynamic query ORM Laravel 4.2

Alright I have a GeneralModel written in CodeIgniter and a friend asked me if I could convert it into Laravel 4.2 for him. I was working on this and I think I have most of it correct but I am getting stuck at the select statement.
In CodeIgniter I have the following:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
if($field != FALSE){
// WHERE in case of FIELD / VAL :)
$this->db->where($field, $val);
}
$query = $this->db->get($table);
if($multiple == 1){
// Multiple rows
return $query->result_array();
} else {
// One row
return $query->row_array();
}
}
Does anyone here knows how I can convert this function into Laravel 4.2 syntax?
I currently have:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
$result = DB::table($table);
}
I got stuck pretty quickly since I have no idea how I can achieve the same in Laravel 4.2 with splitting up the sections of the query like I did with CodeIgniter.
You can chain methods in the same way:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if ($field != FALSE) {
// WHERE in case of FIELD / VAL :)
$query->where($field, $val);
}
if ($multiple)
return $query->get();
else
return $query->first();
}
Laravel is similar in that you can use the Fluent Query Builder to build your queries in multiple stages prior to actually making the query. Once you know this, the translation is pretty straightforward:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if($field){
// WHERE in case of FIELD / VAL :)
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
I don't think it's really good practice relying on Fluent though inside of an Eloquent model, but there are cases where that can't be helped. If the current objective is to convert the project to Laravel, there's probably calling code relying on the fact that this method exists. Converting the function to use Eloquent rather than Fluent will change the function's signature and cause other parts of the code to break, but it would look like this:
public function getData($multiple = true, $field = false, $val = false)
{
$query = $this;
if($field) {
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
The calling code itself can be modified to do the exact same function in Laravel like this:
// Instead of...
$result = $model->getData(1, 'field', 'value');
// You can do this:
$result = $model->where('field', 'value')->get();
// Or this if you'd rather not have multiple:
$result = $model->where('field', 'value')->first();
Using this function inside Eloquent (IMHO) in the long run doesn't really save you much, and instead is mostly just clutter.

Array as parameter (PHP) : Error :Undefined variable

I'm trying to call a function and pass an array and other variables to it. this is the code I use to do that :
function fnGetElementsById($ArrCols, $tableName, $id) {
while($arrCols[$i])
{
if($i != 0)
{
$sql = $sql.',';
}
$sql = $sql.$arrCols[$i].' ';
$i++;
} }
the while line is the error or notice line and when I test with var_dump, the array is empty.
the calling code :
$arrCols = array(
0=>'marque',
1=>'prix'
);
$CDB->fnGetElementsById($arrCols, 'Portables', $_POST['id1']);
thank you
You haven't defined $i before the while loop is invoked. Therefore you are basically trying this:
while($arrCols[null]) {
Also your parameter is $ArrCols and the variable name in the while conditional is $arrCols (lowercase first letter).
You need to fix both of these.
You have a case issue.
function fnGetElementsById($ArrCols, $tableName, $id) {
while($arrCols[$i])
Should be
function fnGetElementsById($arrCols, $tableName, $id) {
while($arrCols[$i])
Notice change from ArrCols to arrCols.
Also you did not initialize your $i variable.
Please set it to 0 before using.

Match function parameters from an associative array and function call in PHP

I have an associative array in the following form:
$params = array(
'paramName_4'=>'param_4',
'paramName_2'=>'param_2',
// ...,
'paramName_6'=>'param_6',
);
and I also have a function myFunction defined as:
public function myFunction($paramName_1, $paramName_2, $paramName_3, ....);
Does a a "parsing" function exist in PHP so that I can call function myFunction by matching the parameters (even if they are not sorted wrt the myFunction's parameter sequence)? In other words, can I do
my_magic(__NAMESPACE__.'\\myFunction', $params);
Does this "magic" function does exist? If not, how can I implement it?
You can implement it using reflection. Here's how:
// The input is the array of arguments and the function name
$arguments = array(....);
$functionName = __NAMESPACE__.'\\myFunction';
$reflector = new \ReflectionFunction($functioName);
$params = $reflector->getParameters();
$values = array();
foreach ($params as $param) {
$name = $param->getName();
$isArgumentGiven = array_key_exists($name, $arguments);
if (!$isArgumentGiven && !$param->isDefaultValueAvailable() {
die ("Parameter $name is mandatory but was not provided");
}
$values[$param->getPosition()] =
$isArgumentGiven ? $arguments[$name] : $param->getDefaultValue();
}
// You can now call the function:
call_user_func($functionName, $values);
Yes, you can use Reflection as per #Jon's example, but if the problem is just that the params aren't in the right order, why not just use ksort() or uksort() to put them in the right order.
Then you can use call_user_func_array(). Problem solved.
$params = array(....);
uksort($params, function($a,$b) {
//sort the params into the known order....
$sortOrder = array('param1','param2','param3','param4');
return (array_search($a, $sortOrder) > array_search($b, $sortOrder)) ? -1 : 1;
});
//now that $params is in the right order we can do this....
$retVal = call_user_func_array($func, $params);
I've hard-coded the param order here, because it's the most efficient way. If you are calling a function where you don't know the correct param order in advance, then yes, you'll need to use reflection. But I would think that's fairly unlikely (passing an unknown params list into an unknown function sounds like a goldmine for hackers)
Here is a library which does the argument resolving for a given function/method: ArgumentsResolver.

Codeigniter issue with escaping values when passing array to query with "in" in the where clause

I have the function below in my model for a codeigniter project, and the variable $id is an array and for example, contains (1,2,3). Now that i'm revisiting it, I think that i'm not actually escaping my array $id. I think I would have to change the line
$this->db->escape($id)
to
$id = $this->db->escape($id)
If I do that, then it puts single quotes around every element in the array and treats it as one long string like this: '(1,2,3)'.
Can someone confirm that I am not actually escaping my variable and either suggest a solution or let me know if this is a bug within the codeigniter framework?
function get_ratings($id)
{
$this->db->escape($id); // had to manually escape the variable since it's being used in an "in" in the where clause.
$sql = "select * from toys t
where t.toy_id in ($id)";
$query = $this->db->query($sql, $id);
if($query->num_rows() > 0)
{
return $query->result_array();
}
else
{
return false;
}
}
You may be interested in using the CI Active Record class:
Beyond simplicity, a major benefit to using the Active Record features is that it allows you to create database independent applications, since the query syntax is generated by each database adapter. It also allows for safer queries, since the values are escaped automatically by the system.
Your rewritten query would look like this (assuming $id is an array):
$this->db->where_in('toy_id', $id)->get('toys');
Aside: I will admit I am a bit confused, as it looks like $ids would be a more appropriate variable name, and the way you are using it in the query, I would assume it is a string...
If active record is not your thing, you may also find Query Bindings to be useful:
The secondary benefit of using binds is that the values are automatically escaped, producing safer queries. You don't have to remember to manually escape data; the engine does it automatically for you.
EDIT: Looking back on this later, it looks like this is what you're trying to do. In that case, try replacing:
$sql = "select * from toys t where t.toy_id in ($id)";
With:
$sql = "select * from toys t where t.toy_id in (?)";
And pass $id as the second argument to query(), but as a comma separated string (implode(',', $id) if $id is indeed an array).
Otherwise you may want to use $this->db->escape_str().
$this->db->escape_str() This function escapes the data passed to it, regardless of type.
Here is an excerpt from the source code of the mysql driver to maybe put your mind at ease.
function escape_str($str, $like = FALSE)
{
if (is_array($str))
{
foreach ($str as $key => $val)
{
$str[$key] = $this->escape_str($val, $like);
}
return $str;
}
// continued...
It loops through arrays and escapes their values.
It does indeed seem that $this->db->escape is not going to work for arrays.
$this->db->escape() This function determines the data type so that it can escape only string data.
Here is the source:
function escape($str)
{
if (is_string($str))
{
$str = "'".$this->escape_str($str)."'";
}
elseif (is_bool($str))
{
$str = ($str === FALSE) ? 0 : 1;
}
elseif (is_null($str))
{
$str = 'NULL';
}
return $str;
}
Looks like it ignores arrays.
Anyways, hope you find a solution that works for you. My vote is for Active Record.
What you want to do is escape the individual values in the array. So you can use array_map on the array first.
$id = array_map('some_escape_function', $id);
See: http://php.net/manual/en/function.array-map.php
Then you can do:
$in = join(",",$id);
Your SQL would then be:
WHERE t.toy_id in ($in)
Which gives you:
WHERE t.toy_id in ('1','2','3')
You could try something like this:
$sql = 'select * from toys t where t.toy_id in ('.
join(',',array_map(function($i) {
return $this->db->escape($i);
}, $id)).');';
*Disclaimer: I'm not where I can access my PHP/MySQL server right now, so I haven't validated this. Some modification and/or tweakage may be necessary.
Here's the solution I'm using for this, with CI 2.1.2:
1) Copy /system/database/DB.php to application/database/DB.php, and around line 123, make it look like:
...
if ( ! isset($active_record) OR $active_record == TRUE)
{
require_once(BASEPATH.'database/DB_active_rec.php');
require_once(APPPATH.'database/MY_DB_active_rec' . EXT);
if ( ! class_exists('CI_DB'))
{
eval('class CI_DB extends MY_DB_active_record { }');
}
}
...
2) Create MY_Loader.php in application/core:
class MY_Loader extends CI_Loader
{
function __construct()
{
parent::__construct();
log_message('debug', 'MY Loader Class Initialized');
}
public function database($params = '', $return = FALSE, $active_record = NULL) {
// Grab the super object
$CI = & get_instance();
// Do we even need to load the database class?
if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) {
return FALSE;
}
//require_once(BASEPATH . 'database/DB.php');
require_once(APPPATH . 'database/DB' . EXT);
if ($return === TRUE) {
return DB($params, $active_record);
}
// Initialize the db variable. Needed to prevent
// reference errors with some configurations
$CI->db = '';
// Load the DB class
$CI->db = & DB($params, $active_record);
}
}
3) Create application/database/MY_DB_active_rec.php:
class MY_DB_active_record extends CI_DB_active_record {
public function __construct($params)
{
parent::__construct($params);
log_message('debug', 'MY Active Record Database Driver Class Initialized');
}
private function _array_escape(&$str)
{
$str = "'" . $this->escape_str($str) . "'";
}
function escape($str)
{
if (is_array($str))
{
array_walk($str, array($this, '_array_escape'));
return implode(',', $str);
}
elseif (is_string($str))
{
$this->_array_escape($str);
}
elseif (is_bool($str))
{
$str = ($str === FALSE) ? 0 : 1;
}
elseif (is_null($str))
{
$str = 'NULL';
}
return $str;
}
}
Then you just pass in an array of values:
$in_data = array(1, 2, 3);
$this->db->query('SELECT * FROM table WHERE id IN(?)', array($in_data));
It's not pretty, but it seems to do the trick!
Code Igniter v3 now automaticly escapes array values :
http://www.codeigniter.com/userguide3/database/queries.html
Query Bindings
Bindings enable you to simplify your query syntax by letting the system put the queries together for you. Consider the following example:
$sql = "SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?";
$this->db->query($sql, array(3, 'live', 'Rick'));
The question marks in the query are automatically replaced with the >values in the array in the second parameter of the query function.
Binding also work with arrays, which will be transformed to IN sets:
$sql = "SELECT * FROM some_table WHERE id IN ? AND status = ? AND author = ?";
$this->db->query($sql, array(array(3, 6), 'live', 'Rick'));
The resulting query will be:
SELECT * FROM some_table WHERE id IN (3,6) AND status = 'live' AND author = 'Rick'
The secondary benefit of using binds is that the values are automatically escaped, producing safer queries. You don’t have to remember to manually escape data; the engine does it automatically for you.
To bind them you can do the following:
$queryParams = [];
// to add the appropriate amount of bindings ?
$idBindings = str_replace(' ', ',', trim(str_repeat("(?) ", count($ids))));
// add each id with int validation
foreach ($ids as $id) {
if(is_int(intVal($id)) == TRUE){
array_push($queryParams, intVal($id));
}
}
// the other option commented out below is to merge without checking -
// note: sometimes values look like numeric values but are actually strings
//queryParams = array_merge($queryParams, $ids);
$sql = "select * from toys t where t.toy_id in ('. $idBindings .')";
$query = $this->db->query($sql, $queryParams );

Categories