Codeigniter handle database error without num_rows() - php

I'm having trouble finding a simple method for handling database errors in CI. For instance, I can't insert duplicate entries in my database table. If I try to, I get a 1062 database error.
The most common solution suggested is to check if the entry already exists and use
$query->num_rows() > 0
in a if-statement to prevent an error. That method seems redundant to me because I'm performing an extra query. Ideally I want to check if an error occurs in my main query or if a row is affected.
I found the following functions that may help
$this->db->affected_rows()
$this->db->_error_message()
however I'm not sure how to use them.
I tried in my Model:
$this->db->insert('subscription', $data);
return $this->db->affected_rows();
To my understanding that should return the number of effected rows. Then in my controller I added:
$affected = $this->Subscribe_model->subscribe($data);
if ($affected < 1)
{
//display error message in view
}
else
{
$this->Subscribe_model->subscribe($data); //perform query
}
Unfortunately the script stops in the model at $this->db->insert('subscription', $data); if an error occurs and displays the entire database error.

I do not know if this works for $this->db->insert();, but $this->db->query(); will return false if it errors so you could do something like this:
$sql = $this->db->insert_string('subscription', $data);
$sql = $this->db->query($sql)
if(!$sql){
//Do your error handling here
} else {
//query ran successfully
}

Try using #$this->db->insert('subscription', $data);, #, in PHP means "suppress warning".
As an alternate -- if you know that data is safe, or you're willing to use $this->db->insert_string, you could add, on duplicate key to the end of the query.
This should work (untested):
$this->db->simple_query( $this->db->insert_string( 'subscription', $data ) .
' ON DUPLICATE KEY ' .
$this->db->update_string(
'subscription',
$data,
/* your where clause here */ );

Related

Generate The Raw MySQL Query From Laravel Query Builder

How can i get mysql query of a laravel query
Convert:
App\User::where('balance','>',0)->where(...)->get();
To:
SELECT * FROM users WHERE `balance`>0 and ...
use toSql() method of laravel to get the query to be executed like
App\User::where('balance','>',0)->where(...)->toSql();
But Laravel will not show you parameters in your query, because they are bound after preparation of the query. To get the bind parameters, use this
$query=App\User::where('balance','>',0)->where(...);
print_r($query->getBindings() );
enable the query log as DB::enableQueryLog() and then output to the screen the last queries ran you can use this,
dd(DB::getQueryLog());
you can add this function to your helpers
function getRealQuery($query, $dumpIt = false)
{
$params = array_map(function ($item) {
return "'{$item}'";
}, $query->getBindings());
$result = str_replace_array('\?', $params, $query->toSql());
if ($dumpIt) {
dd($result);
}
return $result;
}
and use like this:
getRealQuery(App\User::where('balance','>',0)->where(...),true)
Method 1
To print a single query, use toSql() method of laravel to get the query to be executed like
App\User::where('balance','>',0)->where(...)->toSql();
Method 2
Laravel can optionally log in memory all queries that have been run for the current request. But in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory, so you should avoid this.
To enable the log, you may use the enableQueryLog method as
DB::connection()->enableQueryLog();
To get an array of the executed queries, you may use the getQueryLog method as
$queries = DB::getQueryLog();
you can get more details here Laravel Enable Query Log
Method 3
Another approach to display all queries used in Laravel without enabling the query log install the LaravelDebugBar from here Laravel Debug Bar.
It is a package that allows you to quickly and easily keep tabs on your application during development.
To print the raw sql query, try:
DB::enableQueryLog();
// Your query here
$queries = DB::getQueryLog();
print_r($queries);
Reference
Here is a helper function who tells you the last SQL executed.
use DB;
public static function getLastSQL()
{
$queries = DB::getQueryLog();
$last_query = end($queries);
// last_query is the SQL with with data binding like
// {
// select ? from sometable where field = ? and field2 = ? ;
// param1,
// param2,
// param3,
// }
// which is hard to read.
$last_query = bindDataToQuery($last_query);
// here, last_query is the last SQL you have executed as normal SQL
// select param1 from sometable where field=param2 and field2 = param3;
return $last_query
}
Here is the bindDataToQuery function, who fill the '?' blanks with real params.
protected static function bindDataToQuery($queryItem){
$query = $queryItem['query'];
$bindings = $queryItem['bindings'];
$arr = explode('?',$query);
$res = '';
foreach($arr as $idx => $ele){
if($idx < count($arr) - 1){
$res = $res.$ele."'".$bindings[$idx]."'";
}
}
$res = $res.$arr[count($arr) -1];
return $res;
}
It is so strange that the laravel haven't support any way to get the raw sql easily, it is now version 6 after all...
Here's a workaround I used by myself to quickly get the raw sql with parameters without installing any extension...
Just deliberately make your original sql WRONG
Like change
DB::table('user')
to
DB::table('user1')
where the table "user1" does not exist at all!
Then run it again.
Sure there will be an exception reported by laravel.
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'user1' doesn't exist (SQL: ...)
And now you can see the raw sql with parameters is right after the string "(SQL:"
Change back from the wrong table name to the right one and there you go!
In Laravel 5.4 (I didn't check this in other versions), add this function into the
"App"=>"Providers"=>"AppServiceProvider.php" .
public function boot()
{
if (App::isLocal()) {
DB::listen(
function ($sql) {
// $sql is an object with the properties:
// sql: The query
// bindings: the sql query variables
// time: The execution time for the query
// connectionName: The name of the connection
// To save the executed queries to file:
// Process the sql and the bindings:
foreach ($sql->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
} else {
if (is_string($binding)) {
$sql->bindings[$i] = "'$binding'";
}
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
$query = vsprintf($query, $sql->bindings);
// Save the query to file
/*$logFile = fopen(
storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
'a+'
);*/
Log::notice("[USER] $query");
}
);
}
}
After that install,
https://github.com/ARCANEDEV/LogViewer
and then you can see every executed SQL queries without editing the code.
To get mysql query in laravel you need to log your query as
DB::enableQueryLog();
App\User::where('balance','>',0)->where(...)->get();
print_r(DB::getQueryLog());
Check reference : https://laravel.com/docs/5.0/database#query-logging
Instead of interfering with the application with print statements or "dds", I do the following when I want to see the generated SQL:
DB::listen(function ($query) {
Log::info($query->sql, $query->bindings);
});
// (DB and Log are the facades in Illuminate\Support\Facades namespace)
This will output the sql to the Laravel log (located at storage/logs/laravel.log). A useful command for following writes to this file is
tail -n0 -f storage/logs/laravel.log
A simple way to display all queries used in Laravel without any code changes at all is to install the LaravelDebugBar (https://laravel-news.com/laravel-debugbar).
As part of the functionality you get a tab which will show you all of the queries that a page has used.
Try this:
$results = App\User::where('balance','>',0)->where(...)->toSql();
dd($results);
Note: get() has been replaced with toSql() to display the raw SQL query.
A very simple and shortcut way is below
Write the name of column wrong like write 'balancedd' in spite of 'balance' and the query will be displayed on error screen when you execute code with all the parameters and error that column not found.
DB::enableQueryLog();
(Query)
$d= DB::getQueryLog(); print"<pre>"; print_r ($d); print"</pre>";
you will get the mysql query that is just run.
There is actually no such thing in Laravel and even PHP, since PHP internally sends the parameters with query string to the database where it (possibly) become parsed into raw query string.
The accepted answer is actually optimistic solution, kind of "optionally works".

empty value after mysql update php

i made a lot of research around here and Google but i cannot find an answer to this problem.
I update a field in a MySQL database with following code:
public function registerPubKey() {
$stmt = $this->cn->prepare('UPDATE sb_user SET pubkey= ? WHERE email= ?');
$exres = $stmt->execute(array($this->info["pubkey"], $this->info["email"]));
if ($exres == false) {
$resultArray["result"] = "Error registering public key";
echo json_encode($resultArray);
exit;
}
$resultArray["result"] = "success";
echo json_encode($resultArray);
}
I'm sure that all works except that the field in the database is empty. I dumped the private variable $info and it contains the pubkey (pubkey is a base64 string).
I noticed that if I change the update query with an INSERT, the value is inserted correctly!
It's likely because you're trying to UPDATE non existent rows. Try adding a ON DUPLICATE KEY before. See INSERT ... ON DUPLICATE KEY UPDATE Syntax. UPDATE returns nothing if the row does not exist.
I ran into a similar issue and validated that:
the row existed, and
the execute parameters were valid and correct
The PDO::errorInfo() function can provide insight into what's actually happening to cause the update to fail:
if (! $stmt->execute($params) ) {
$resultArray["result"] = print_r($stmt->errorInfo(), true);
}
In my case, I got the message The user specified as a definer ('user'#'172.20.%.%') does not exist. Since this was a database snapshot restored to a different subnet, the error message makes sense and the user in-fact did not exist.

Update query insert zero in table in ci

Update query insert zero in table everytime.
I have prtinted the query.From phpmyadmin the lastquery working fine.updated with same value
But when db active query then it has updating 0.
tbl_setitbl
set_id(primary key)
reference(text)`
Here is my code.
public function edit_set($id,$setvalue)
{
$data = array('reference' => $setvalue);
$this->db->where('set_id', $id);
$this->db->update('tbl_setitbl', $data);
if($this->db->affected_rows())
return true;
else
return false;
}
I have tried this code also.
$this->db->where('set_id', $id);
$this->db->update('tbl_setitbl', array('reference' => $setvalue));
echo $this->db->last_query();
UPDATE tbl_setitbl SET reference = 'hhhhhhhh' WHERE set_id = 1
Sorry every one...
Get solved
actually the problem is in controller.
query has run two times as redirection has not doing properly
see the result by using $this->db->last_query() then verify the sql code if it is similiar to the sql code that you have tried in phpmyadmin

Codeigniter: Active Records Insert Unique values

I am importing GMail contacts from Google API and just want to persist unique email ids into database.
Is it possible to insert unique records using codeigniter's Active Record?
Does CodeIgniter provide it out of the box?
If I make the column unique the query throws exception. After digging into documentation I understood that CodeIgniter doesn't provide try catch blocks.
your email field have to be unique in your table indexes.
$query_string = $this->db->insert_string('table', $data);
$query_string = str_replace('INSERT INTO', 'INSERT IGNORE INTO', $query_string);
$req = $this->db->query($query_string);
if($req->affected_rows() == 1) {
//data inserted
} else {
//email exists already
}
If you use the IGNORE keyword, errors that occur while executing the
INSERT statement are treated as warnings instead. For example, without
IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY
value in the table causes a duplicate-key error and the statement is
aborted. With IGNORE, the row still is not inserted, but no error is
issued. Data conversions that would trigger errors abort the statement
if IGNORE is not specified. With IGNORE, invalid values are adjusted
to the closest values and inserted; warnings are produced but the
statement does not abort.
MySQL INSERT syntax
CI Database Helper
You can create a base model (application/core/MY_Model.php) and implement a save function to insert if new and update if exists. Extend your model from it.
This is an extract from http://thephpcode.com/blog/codeigniter/a-smart-codeigniter-model
public function save($data,$tablename="")
{
if($tablename=="")
{
$tablename = $this->table;
}
$op = 'update';
$keyExists = FALSE;
$fields = $this->db->field_data($tablename);
foreach ($fields as $field)
{
if($field->primary_key==1)
{
$keyExists = TRUE;
if(isset($data[$field->name]))
{
$this->db->where($field->name, $data[$field->name]);
}
else
{
$op = 'insert';
}
}
}
if($keyExists && $op=='update')
{
$this->db->set($data);
$this->db->update($tablename);
if($this->db->affected_rows()==1)
{
return $this->db->affected_rows();
}
}
$this->db->insert($tablename,$data);
return $this->db->affected_rows();
}
If your data comes from a from, CI provides a form_validation class that can validate your form on the server side.By form_validation has a rule called is_unique its checks if the given value is already exist on the database or not. you can see a complete and clear explanation here
Or, you can check it manually before inserting your email in that unqiue column.
$this->db->select('email');
$this->db->where(array('email'=>$email));
$query = $this->db->get('yourtable');
if($query->num_rows() > 0){
// the query returned data, so the email already exist.
}else{
// the email not exists, so you can insert it.
}

MySQL query sent successfully, yet database field stays empty

The following 2 queries are the result of an echo in php:
UPDATE glymping_userdata
SET current_location_gps = '51.9171115;4.484812'
WHERE id = 1
and
UPDATE glymping_user_has_appointments
SET status = 'enroute',
start_location_gps = '51.9171115;4.484812'
WHERE userId = 1
AND appointmentId = 47
Both queries work when entered manually in the database and all fields are filled correctly. When I let the php file run the queries, the queries are like shown above, but the "start_location_gps" and the "current_location_gps" are empty.
The values in the queries are strings and the database fields are a varchar(30). Yet the fields in the database are empty.
The location value is received from a post method.
Does anyone knows what I am forgetting or doing wrong?
EDIT:
php example
public function SendQuery($query)
{
$results = $this->mysqli->query($query);
return $results;
}
public function UpdateUserLocation($currentLocationGps)
{
$query = "UPDATE ".DB_PREFIX."userdata
SET current_location_gps = '{$currentLocationGps}'
WHERE id = ".$this->userId;
//echo $query;
$this->db->SendQuery($query);
}
Your current code doesn't check the return value of mysqli_query; the query might fail "silently". It could also be that the query does not affect any records in the database becaue of wrong values in the WHERE clause.
Try it with
if ( !$this->db->SendQuery($query) ) {
// query failed: syntax error, connection lost, access denied,duplicate entries, ...
trigger_error($this->mysqli->error);
}
else {
if ( 0 < $this->mysqli->affected_rows ) {
// WHERE clause doesn't match any record, no values changed, ...
trigger_error('no rows affected');
}
}
Your query might also be prone to sql injections, please check http://php.net/manual/en/security.database.sql-injection.php

Categories