My hosting provider has PHP 5.3 without mysqlnd installed, and thus it returns an error when I call mysqli_stmt_get_result()
is there any workaround to achieve the same functionality without having to install mysqlnd?
I don't want to change 100's of functions, if there's an easier method, any help will be appreciated :)
I went through a lot of trouble on a server where mysqlnd wasn't available, and had a lot of headaches.
If you don't have mysqlnd installed/loaded whatever, you will get an undefined reference when trying to call mysqli_stmt_get_result().
I wrote my own mysqli_stmt_get_result() and a mysqli_result_fetch_array() to go with it.
<?php
class iimysqli_result
{
public $stmt, $nCols;
}
function iimysqli_stmt_get_result($stmt)
{
/** EXPLANATION:
* We are creating a fake "result" structure to enable us to have
* source-level equivalent syntax to a query executed via
* mysqli_query().
*
* $stmt = mysqli_prepare($conn, "");
* mysqli_bind_param($stmt, "types", ...);
*
* $param1 = 0;
* $param2 = 'foo';
* $param3 = 'bar';
* mysqli_execute($stmt);
* $result _mysqli_stmt_get_result($stmt);
* [ $arr = _mysqli_result_fetch_array($result);
* || $assoc = _mysqli_result_fetch_assoc($result); ]
* mysqli_stmt_close($stmt);
* mysqli_close($conn);
*
* At the source level, there is no difference between this and mysqlnd.
**/
$metadata = mysqli_stmt_result_metadata($stmt);
$ret = new iimysqli_result;
if (!$ret) return NULL;
$ret->nCols = mysqli_num_fields($metadata);
$ret->stmt = $stmt;
mysqli_free_result($metadata);
return $ret;
}
function iimysqli_result_fetch_array(&$result)
{
$ret = array();
$code = "return mysqli_stmt_bind_result(\$result->stmt ";
for ($i=0; $i<$result->nCols; $i++)
{
$ret[$i] = NULL;
$code .= ", \$ret['" .$i ."']";
};
$code .= ");";
if (!eval($code)) { return NULL; };
// This should advance the "$stmt" cursor.
if (!mysqli_stmt_fetch($result->stmt)) { return NULL; };
// Return the array we built.
return $ret;
}
?>
This related question has another workaround to get data without installing mysqlnd. It puts the data into an associative array.
Mysqli - Bind results to an Array
The solution from Daan is very nice! For this, i have to say thank you!
The point is, that i had, based on this, developed a class which works with mysqlnd, when it's there and Daan's alternative when it's missing.
I have built in fetchAssoc, fetchAllAssoc/Array, num_rows as methods. It's still in development and part of youphptube. This maybe also helps Ehab (whish for fetchAssoc).
https://github.com/DanielnetoDotCom/YouPHPTube/blob/master/objects/mysql_dal.php
Usage:
$sql = "SELECT * FROM users WHERE id = ?";
$res = sqlDAL::readSql($sql,"i",array($users_id));
$fullData = sqlDAL::fetchAllAssoc($res);
// $data = sqlDAL::fetchAssoc($res); $data2 = sqlDAL::fetchAssoc($res); // or like this
// $countedRows = sqlDAL::num_rows($res); // or like this
sqlDAL::close($res);
I would made this as a sub-post to Daan's answer, but my reputation is too small.
Related
I am getting this error in Apache2 errors logs:
PHP Fatal error: Function 'ns1:getClients' doesn't exist
I checked to see why the PHP Soap Server is not locating the method in the class Client_API and can't see any course here's the index.php file:
require(INCLUDES_DIR.'BaseService.class.php');
require($interfaceFile);
require($serviceFile); // loads /var/www/official-productionapi/includes/Client.service.php
//...
$server = new SoapServer(null, array ('uri'=>'', 'trace' => 1, 'connection_timeout' => intval(600)));
$server->setClass($serviceName.CLASS_SUFFIX); // -- e.g. 'Client_API'
$server->handle();
The Class containing the missing method:
class Client_API extends BaseService implements Client_API_Interface
{
public function getClients($range = 10, $search, $accessUserID = null)
{
if(!$this->Authenticated){
throw new SoapFault('Server', 'Authorization failed: Wrong username or password');
}
$max = 100;
$range = (int)$range;
if($range > $max){
$range = $max;
}
$clients = array();
$db = Database::getInstance();
if(null !== $accessUserID){
$sql = "SELECT * FROM clients as c, users_clients_access as uac WHERE c.ClientID = uac.ClientID AND uac.UserID = '".$db->escape($accessUserID)."' AND c.IsShopAssistClient = 0 AND (c.ClientName LIKE '".$db->escape($search)."%' OR c.Tag LIKE '".$db->escape($search)."%') ORDER BY c.ClientName Asc LIMIT $range";
}else{
$sql = "SELECT * FROM clients WHERE IsShopAssistClient = 0 AND (ClientName LIKE '".$db->escape($search)."%' OR Tag LIKE '".$db->escape($search)."%') ORDER BY ClientName Asc LIMIT $range";
}
$clientQ = $db->query($sql);
while($client = $db->fetch_array($clientQ)){
$arr = array();
$arr['PClientName'] = $client['ClientName'];
$arr['PClientTag'] = $client['Tag'];
$clients[$client['ClientID']] = $arr;
}
return $clients;
}
//...
Any help would be appreciated, I have been thinking if it has something to do with PHP version mismatch, it was working on version 5.3.3 but it's not on version 5.3.10. So only minor differences.
I have been able to solve this issue by setting uri option to 'uri'=>'api'. Seems like leaving it blank wasn't a good idea. It still boggles me how it works on the same version of PHP on Windows just fine.
This post led me to my answwer: Issues with SOAP in non-WSDL mode.
I am looking for a long term solution to accommodate T-SQL queries that need to use late binding. Late binding syntax with MS-SQL is a pain and is unique.
When it comes to T-SQL late binding we need to DECLARE and SET, like
DECLARE #id int
SET #id = 1
SELECT * FROM users
WHERE user_id = #id;
Now Zend Framework 2 builds queries like
$select = new Sql\Select();
$select->from(['users']);
$select->columns(['*']);
$select->where->equalTo('user_id', '#id');
// Create the statement object
$stmt = $sql->prepareStatementForSqlObject();
$stmt->prepare();
$stmt->execute(['#id' => 1]);
Now in ZF2's Statement object's prepare() method I can prefix my DECLARE and SET to the already existing $sql, like so:
public function prepare($sql = null, array $options = [])
{
if ($this->isPrepared) {
throw new Exception\RuntimeException('Already prepared');
}
$sql = ($sql) ?: $this->sql;
$options = ($options) ?: $this->prepareOptions;
$pRef = &$this->parameterReferences;
// change substr_count($sql, '?') <-> TO |-> substr_count($sql, '#')
for ($position = 0, $count = substr_count($sql, '?'); $position < $count; $position++) {
if (!isset($this->prepareParams[$position])) {
$pRef[$position] = ['', SQLSRV_PARAM_IN, null, null];
} else {
$pRef[$position] = &$this->prepareParams[$position];
}
}
// <!-- Beg of custom stuff. I can grab the $sql string, that we built up here, with $this->sql, and prefix it with the T-SQL required DECLARE and SET. -->
// We can get #id and 1 through the execute()'s call and the parameter Container.
$prependSQL = "DECLARE #id int";
$prependSQL .= "SET #id = 1";
$prependSQL .= $this->sql;
$this->sql = $prependSQL;
$sql = $this->sql;
// <!-- End of custom stuff -->
$this->resource = sqlsrv_prepare($this->sqlsrv, $sql, $pRef, $options);
$this->isPrepared = true;
return $this;
}
Is this how I should be doing this? I feel like I am undermining ZF2's DB abstraction layer. Any direction or input would be great on how I am suppose to do this.
I am trying to display records using PDO LIKE query, but I am getting this error message can I know how to solve this.
This is my code:
$rs = new JSONRecordSet();
$searchbooksSQL = "SELECT Title FROM l_stock WHERE Title LIKE ?";
$params = array("%$term%");
echo $rs->getRecordSet($searchbooksSQL, $params);
This is the getRecordSet code:
class R_RecordSet {
function getRecordSet($sql, $params = null) {
if (is_array($params)) {
$this->stmt = $this->db->prepare($sql);
// execute the statement passing in the named placeholder and the value it'll have
$this->stmt->execute($params);
} else {
$this->stmt = $this->db->query($sql);
}
return $this->stmt;
}
}
class JSONRecordSet extends R_RecordSet {
function getRecordSet($sql, $elementName = "ResultSet", $params = null) {
$stmt = parent::getRecordSet($sql, $params);
$recordSet = $stmt->fetchAll(PDO::FETCH_ASSOC);
$nRecords = count($recordSet);
if ($nRecords == 0) {
$status = 'error';
$message = json_encode(array("text" => "No records found"));
$result = '[]';
} else {
$status = 'ok';
$message = json_encode(array("text" => ""));
$result = json_encode($recordSet);
}
return "{\"status\": \"$status\", \"message\":$message, \"$elementName\" :{\"RowCount\": $nRecords ,\"Result\": $result}}";
}
}
The error message i am getting is "Notice: Array to string conversion"
getRecordSet() is defined as:
function getRecordSet($sql, $elementName = "ResultSet", $params = null) {
however, you are calling it as:
echo $rs->getRecordSet($searchbooksSQL, $params);
You will need to modify your code to pass in an appropriate $elementName parameter. (The default is probably reasonable.)
echo $rs->getRecordSet($searchbooksSQL, 'ResultSet', $params);
Additionally, you should probably use json_encode() to generate the final result from JSONRecordSet::getRecordSet(), rather than building it up with string concatenation. It will make the code easier to read and understand.
Also, your two implementations of getRecordSet() are incompatible with each other, according to the Liskov Substitution Principle due to the change in the semantics of the input parameters, and is likely what led you to the parameter mismatch at your call site in the first place. You probably want to re-order JSONRecordSet::getRecordSet() parameters to:
function getRecordSet($sql, $params = null, $elementName = 'ResultSet') {
I have this part of code working fine:
$array_stats_raw = $db->query($query);
$array_statistics[$name] = $array_stats_raw->fetchArray(SQLITE3_ASSOC);
However I have many different queries that I have to pass in the same code so I am trying to put it in a function and call the function instead of repeating this code many times.
I tried the following:
function sqlite_query123($dbhandle,$query1,$name)
{
$result = $dbhandle->query($query1);
$result1[$name] = $result->fetchArray(SQLITE3_ASSOC);
return $result1;
}
$array_statistics[$name] = sqlite_query123($db, $query, $name);
What am I doing wrong? Sorry for asking a novice question but I feel like I am missing something simple and can't figure it out what?
Incase it is not a typo in the question, you misspelt $result as $results :
function sqlite_query123($dbhandle,$query1,$name)
{
$result = $dbhandle->query($query1);
$result1[$name] = $result->fetchArray(SQLITE3_ASSOC);
return $result1;
}
UPDATE :
Try this
function sqlite_query123($dbhandle,$query1,$name)
{
$result = $dbhandle->query($query1);
return $result->fetchArray(SQLITE3_ASSOC);
}
The following also worked:
function sqlite_query123($dbhandle,$query1,$name)
{
$result = $dbhandle->query($query1);
$result1[$name] = $result->fetchArray(SQLITE3_ASSOC);
return $result1[name];
}
I have the following model function and I was wanting to know how I could improve it and also pull the needed $row out when needed so that I dont get a PHP error.
How I am pulling the required data:
$data['companyName'] = $this->core_model->companyDetails('coreCompanyName');
Errors:
Undefined property: stdClass::$coreContactName
Undefined property: stdClass::$coreContactEmail
Model:
function companyDetails()
{
$this->db->select('coreCompanyName, coreContactName, coreContactEmail');
$this->db->from('core');
$whereData = array('coreCompanyName' => $companyName, 'coreContactName' => $companyContactName, 'coreContactEmail' => $companyContactEmail);
$this->db->where($whereData);
$query = $this->db->get();
$result = '';
if ($query->num_rows() > 0)
{
foreach ($query->result() as $row)
{
$result .= $row->coreCompanyName;
$result .= $row->coreContactName;
$result .= $row->coreContactEmail;
}
}
return $result;
}
It should be like this
$this->db->select('coreCompanyName, coreContactName, coreContactEmail');
not
$this->db->select('coreCompanyName','coreContactName','coreContactEmail');
See reference http://codeigniter.com/user_guide/database/active_record.html#select
To limit to a specific set of records, use the where() function. e.g.
$this->db->where('companyId', $companyId);
<?php
/**
*
* WHERE ARE : $companyName, $companyContactName, $companyContactEmail being defined ?
* WHY return 'companyName' WHEN You are quering based on the '$companyName' ???
* Your query wil fail with out it, that that's all your using ?
*
*/
function companyDetails() {
$query = $this->db->query("SELECT companyName FROM core WHERE coreCompanyName = ? AND coreContactName = ? AND coreContactEmail = ? LIMIT 1",
array($companyName, $companyContactName, $companyContactEmail));
return ($query->num_rows() == 1) ? $query->row()->companyName : FALSE;
}
Change:
$this->db->select('coreCompanyName','coreContactName','coreContactEmail');
To:
$this->db->select('coreCompanyName, coreContactName, coreContactEmail');
Now, you said this pulls all the data, but you aren't actually filtering the result. I wonder what the required data is