i am using database handler for my sessions which working fine but now i stack into a problem on authentication.
When user login with username/password i do session_regenerate_id and after that i am trying to select the current session_id.
Here is my code
session_regenerate_id();
echo $checkQ=" SELECT * FROM my_sessions WHERE id='".session_id()."' ";
......
but i dont get any results. The session_id is the correct one.
After finish load the page and copy paste the SQL Command to phpMyAdmin i get the results.
I know thats its stupid but the only reason i can think of is that session_regenerate_id() "is too slow" so when i try to read the session_id at next line the session_id has not created in database yet.
Can anyone help me!
I know it has been a while, I hope you have found an answer since this was posted, but I'll add my solution for posterity's sake.
The call to session_generate_id() will cause the value of session_id() to change:
<?php
$before = session_id();
session_regenerate_id();
$after = session_id();
var_dump($before == $after); // outputs false
This problem manifested for me because in the session write handler I was doing this (without such bogus method names, of course):
<?php
class MySQLHandler
{
function read($id)
{
$row = $this->doSelectSql($id);
if ($row) {
$this->foundSessionDuringRead = true;
}
// snip
}
function write($id, $data)
{
if ($this->foundSessionDuringRead) {
$this->doUpdateSql($id, $data);
}
else {
$this->doInsertSql($id, $data);
}
}
}
The write() method worked fine if session_regenerate_id() was never called. If it was called, however, the $id argument to write() is different to the $id passed to read(), so the update won't find any records with the new $id because they've never been inserted.
Some people suggest to use MySQL's "REPLACE INTO" syntax, but that deletes and replaces the row, which plays merry havoc if you want to have a creation date column. What I did to fix the problem was to hold on to the session ID that was passed to read, then update the session ID in the database during write using the id passed to read as the key:
<?php
class MySQLHandler
{
function read($id)
{
$row = $this->doSelectSql($id);
if ($row) {
$this->rowSessionId = $id;
}
// snip
}
function write($id, $data)
{
if ($this->rowSessionId) {
$stmt = $this->pdo->prepare("UPDATE session SET session_id=:id, data=:data WHERE session_id=:rowSessionId AND session_name=:sessionName");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':rowSessionId', $this->rowSessionId);
$stmt->bindValue(':data', $data);
$stmt->bindValue(':sessionName', $this->sessionName);
$stmt->execute();
}
else {
$this->doInsertSql($id, $data);
}
}
}
I think I'm having the same problem you are having. It's unclear to me whether this is a PHP (cache) feature or a bug.
The issue is that, when using a custom SessionHandler and calling session_regenerate_id(true), the new session is not created until the script terminates. I have confirmed that by doing the same thing you did: SELECTing the new session id from the database. And the new session is not there. However, after the script finishes, it is.
This is how I fixed it:
$old_id = session_id();
// If you SELECT your DB and search for $old_id, it will be there.
session_regenerate_id(TRUE);
$new_id = session_id();
// If you SELECT your DB for either $old_id or $new_id, none will be there.
session_write_close();
session_start();
// If you SELECT your DB for $new_id, it will be there.
Therefore the solution (workaround) I came about was to force PHP to write the session. I hope this helps.
Related
I got a api request that has a parameter in it which is projectname. The problem is when I search for example A the results will be A but when I search for B the result is till A even if I search C the result is still the same. I think the cache saved the first results from the first search string. My question is how could I save every results in every search query without getting the same result based on the search query?
Here is my code
public function getRecordDetails(Request $request){
if(!empty($request->limit)){
$limit = " LIMIT ".$_REQUEST['limit'];
}
else{
$limit= '';
}
if(empty($request->projectname)){
dd('Field is empty');
}
else{
$data = Cache::rememberForever('results', function () use($request) {
$result = DB::connection('mysql2')
->table('xp_pn_ura_transactions')
->whereRaw(DB::raw("CONCAT(block, ' ', street,' ',project_name,' ', postal_code,'')LIKE '%$request->projectname%' order by STR_TO_DATE(sale_date, '%d-%M-%Y') desc"))
->limit($request->limit)
->distinct()
->get();
$count = DB::connection('mysql2')
->table('xp_pn_ura_transactions')
->whereRaw(DB::raw("CONCAT(block, ' ', street,' ',project_name,' ', postal_code,'')LIKE '%$request->projectname%'"))
->count();
return json_encode(array('count'=>$count,'result'=>$result));
});
return $data;
}
}
PS: This question is based here How could I cache every api response results in my query in Laravel? I answered here but this is different problem based on my answer. Thanks for helping.
Laravel find the Cache by the key. You're using results as your key.
So no matter how different request you pass. It still can find the cache by results.
So it will return the first cache you store in results.
$key = "results:".$request->projectname.':' $request->limit;
Cache::rememberForever($key, function () use ($request) {
...
}
This one will store every different projectname you request.
However
Problem 1:
There are so many diff possibilities that user can request.
I don't think it is a good idea to store all these cache. If there are not that much, it is ok.
Solution:
Or you can use remember() instead of rememberForever()
$ttl = ????; // Find the appropriate time to expire the cache
$value = Cache::remember($key, $ttl, function () {});
Problem 2:
There is a $request->limit in your cache.
That means if someone insert or delete a record in that table. next time you request with another limit, you will face the duplicated records.
Solution:
So I think you can clear the cache after you create , update or delete the records.
Because you are using the same cache slug over and over. You should change the cache slug according to the changed input. Adding the $request as a use argument to your function will not magically change the cache slug.
In your case, this should work:
Cache::rememberForever("results_{$request->projectname}", function () use ($request) {
you should add text value after and before key id like bello
Cache::rememberForever('product_'.$product->id.'_key',function ()
});
I got stuck with this problem, I found many posts but seemed it's not useful. So I post again here and hope someone can help me.
Let say I have 2 button, 1 is Start button and 1 is Stop button. When I press start will call ajax function which query very long time. I need when I press Stop will stop immediately this query, not execute anymore.
this is function used to call query and fetch row. (customize Mysqli.php)
public function fetchMultiRowset($params = array()) {
$data = array();
$mysqli = $this->_adapter->getConnection();
$mysqli->multi_query($this->bindParams($this->_sql, $params));
$thread_id = mysqli_thread_id($mysqli);
ignore_user_abort(true);
ob_start();
$index = 0;
do {
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$data[$index] = $row;
$index++;
echo " ";
ob_flush();
flush();
}
$result->free();
}
}
while ($mysqli->more_results() && $mysqli->next_result());
ob_end_flush();
return $data;
}
Function in Model:
public function select_entries() {
$data = null;
try {
$db = Zend_Db_Adapter_Mysqlicustom::singleton();
$sql = "SELECT * FROM report LIMIT 2000000";
$data = $db->fetchMultiRowset($sql);
$db->closeConnection();
} catch (Exception $exc) {
}
return $data;
}
Controller:
public function testAction(){
$op = $this->report_test->select_entries();
}
In AJAX I used xhr.abort() to stop the AJAX function. But it still runs the query while AJAX was aborted.
How do I stop query? I used Zend Framework.
EDIT: I did not look in detail at your program, now I see that not the query itself is taking so long, but the reading of all the data. So just check every 1000 rows, if the ajax call is still active. Ajax Abort.
Solution in case of a long-running SQL-query:
You would have to allow the application to kill database queries, and you need to implement a more complex interaction between Client and Server, which could lead to security holes if done wrong.
The Start-Request should contain a session and a page id (secure id, so not 3 and 4 and 5 but a non-guessable but unique hash of some kind). The backend then connects this id with the query. This could be done in some extra table of the database, but also via comments in the SQL query, like "Session fid98a08u4j, Page 940jfmkvlz" => s:<session>p:<page>.
/* s:fid98a08u4jp:940jfmkvlz */ select * from ...
If the user presses "stop", you send session and page id to the server. The php-code then fetches the list of your running SQL Queries and searches for session and page and extracts the query id.
Then the php sends a
kill query <id>
to the MySQL-server.
This might lead to trouble when not using transactions, and this might damage replication. And even a kill query might take some time in the state 'killing'.
So be sure that you can and want not to split the long running query into subqueries, which check if the request is still valid every few seconds, or that you do not just want to kill the query for cosmetical reasons.
public function smart_query($query, $options = null, $bindoptions = null)
{
// Code to Reconnect incase of timeout
try {
$this->db->query('SELECT * FROM templates');
}
catch (PDOException $e)
{
echo $e;
$pdooptions = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
$this->db = new PDO("mysql:host=localhost;dbname=$this->database", "$this->username", "$this->password", $pdooptions);
}
$this->statement = $this->db->prepare($query);
if($bindoptions != null)
{
$this->bind($bindoptions);
}
$this->execute();
if($options != null)
{
// Return Single Row
if($options['rows'] == 1)
{
return $this->statement->fetch(PDO::FETCH_ASSOC);
}
// Return Multiple Rows
elseif($options['rows'] != 1)
{
return $this->statement->fetchAll(PDO::FETCH_ASSOC);
}
}
}
I've saw this code today, and got really confused.
It looks like he is trying to process a simple query, before doing the actual query.
Why is he checking if the connection is still open?
I thought that PDO only destroys it's connection upon script finishing executing automatically?
Is that correct to check if it's open or closed?
This implements a form of lazy loading.
This first time a query is executed through this class/function, the database connection may not be established yet. This is the purpose of this check, so that the consumer (you) does not have to mind about it.
The connection is then stored in the $this->db class member, for future reuse when you call this method again in the course of your script (and yes, this connection will stay open until the script ends -- unless it is closed explicitely beforehand, of course).
For information, this check is slightly inefficient. A simple $this->db->query('SELECT 1') would suffice, without the need to read a table at all.
I am using latest codeigniter and trying to call stored procedure from my model. Also I am using mysqli as database driver. Now I am having an error when I call two stored procedures. Following is the error:
Error Number: 2014
Commands out of sync; you can't run this command now
call uspTest();
Filename: E:\wamp\www\reonomy-dev\system\database\DB_driver.php
Line Number: 330
Note that when I call a single stored procedure it works fine. Here is the code for model.
class Menus_model extends CI_Model {
function __construct()
{
parent::__construct();
}
public function getMenus()
{
$query = $this->db->query("call uspGetMenus()");
return $query->result();
}
public function getSubMenus()
{
$query = $this->db->query("call uspTest()");
return $query->result();
}
}
Here is the code from controller
class MYHQ extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('menus_model');
}
public function index()
{
$menu = $this->menus_model->getMenus();
$submenu = $this->menus_model->getSubMenus();
}
}
Is there any solution without hacking the core of codeigniter??
I follow the blog of Mr. Tim Brownlaw:
http://ellislab.com/forums/viewthread/73714/#562711
First, modify application/config/config.php, line 55.
$db['default']['dbdriver'] = 'mysqli'; // USE mysqli
Then, add the following into mysqli_result.php that is missing this command for some strange reason (under /system/database/drivers/mysqli/mysqli_result.php).
/**
* Read the next result
*
* #return null
*/
function next_result()
{
if (is_object($this->conn_id))
{
return mysqli_next_result($this->conn_id);
}
}
Then, in your model, add $result->next_result().
Below is my example.
function list_sample($str_where, $str_order, $str_limit)
{
$qry_res = $this->db->query("CALL rt_sample_list('{$str_where}', '{$str_order}', '{$str_limit}');");
$res = $qry_res->result();
$qry_res->next_result(); // Dump the extra resultset.
$qry_res->free_result(); // Does what it says.
return $res;
}
Having the same problem I found another approach which doesn't change the core, but instead uses a small helper.
Edit: The below linked asset is nowhere to be found.
See CoreyLoose post.
https://ellislab.com/forums/viewthread/71141/#663206
I had to make a small adjusment to his helper though. The line
if( get_class($result) == 'mysqli_stmt' )
could possibly produce a warning since the $result sometimes is passed as a boolean. I just put a check prior to this line and now it works perfectly, with no tinkering with the core!
This seems to be a bug in CodeIgniter. How come it's still in there is beyond me.
However, there's a couple of ways to overcome it.
Check here: http://codeigniter.com/forums/viewthread/73714/
Basically, you modify mysqli_result.php to include next_result() function and make sure to call it after every stored proc. call.
Just note that it assumes you're using mysqli as your DB driver... but you can probably do something similar with any other. You can change your driver in /application/config/database.php It's the line that says
$db['default']['dbdriver'] = 'mysql';
by default. Change it to:
$db['default']['dbdriver'] = 'mysqli';
You could also just close/reopen a DB connection between the calls, but I would definitely advise against that approach.
change dbdriver to "mysqli"
put this function to your model and use it to call stored procedure
function call( $procedure )
{
$result = #$this->db->conn_id->query( $procedure );
while ( $this->db->conn_id->next_result() )
{
//free each result.
$not_used_result = $this->db->conn_id->use_result();
if ( $not_used_result instanceof mysqli_result )
{
$not_used_result->free();
}
}
return $result;
}
How do I get Asterisk to forward incoming calls based on matching the incoming call number with a number to forward to? Both numbers are stored in a MySQL database.
Sorry for the long code sample, but more than half of it is debugging code to help you get it set up.
I'm assuming your server already has a modern version of PHP (at /usr/bin/php) with the PDO library, and that you have a database table named fwd_table with columns caller_id and destination.
In /var/lib/asterisk/agi-bin get a copy of the PHP AGI library. Then create a file named something like forward_by_callerid.agi that contains:
#!/usr/bin/php
<?php
ini_set('display_errors','false'); //Supress errors getting sent to the Asterisk process
require('phpagi.php');
$agi = new AGI();
try {
$pdo = new PDO('mysql:host='.$db_hostname.';dbname='.$db_database.';charset=UTF-8', $db_user, $db_pass);
} catch (PDOException $e) {
$agi->conlog("FAIL: Error connecting to the database! " . $e->getMessage());
die();
}
$find_fwd_by_callerid = $pdo->prepare('SELECT destination FROM fwd_table WHERE caller_id=? ');
$caller_id = $agi->request['agi_callerid'];
if($callerid=="unknown" or $callerid=="private" or $callerid==""){
$agi->conlog("Call came in without caller id, I give up");
exit;
}else{
$agi->conlog("Call came in with caller id number $caller_id.");
}
if($find_fwd_by_callerid->execute(array($caller_id)) === false){
$agi->conlog("Database problem searching for forward destination (find_fwd_by_callerid), croaking");
exit;
}
$found_fwds = $find_fwd_by_callerid->fetchAll();
if(count($found_fwds) > 0){
$destination = $found_contacts[0]['destination'];
$agi->set_variable('FWD_TO', $destination);
$agi->conlog("Caller ID matched, setting FWD_TO variable to ''");
}
?>
Then from the dial plan you can call it like this:
AGI(forward_by_callerid.agi)
And if your database has a match, it will set the variable FWD_TO with goodness. Please edit your question if you need more help getting this integrated into your dial plan.
This article should do the trick. It's about 3 lines of code and some simple queries to add and remove forwarding rules.
The solution I was looking for ended up looking like this:
[default]
exten => _X.,1,Set(ARRAY(${EXTEN}_phone)=${DTC_ICF(phone_number,${EXTEN})})
exten => _X.,n(callphone),Dial(SIP/metaswitch/${${EXTEN}_phone},26)
exten => _X.,n(end),Hangup()