Trying to understand how to share my session data between my App and my chat server (Ratchet). I thought using Symfony & Memcache would be easy enough but I just can't seem to get it working.
I am trying to get the user_id out of the session for when somebody sends a message to the chat it will insert the user_id into the database (Chat->onMessage).
Can somebody point me in the right direction?
Flow:
config.php is included on every page
When user logs into the website it executes the $login->processLogin() method
I start my chat server via command line (php server.php)
config.php
<?php
use MyApp\Login;
use MyApp\Session as MySession;
# Define backslash or forward slash for *NIX and IIS systems.
define('DS', DIRECTORY_SEPARATOR);
# Attempt to determine the full-server path to the 'root' folder in order to reduce the possibility of path problems.
define('BASE_PATH', realpath(dirname(__FILE__)).DS);
# Define the complete path to the root of the domain we are at (ie. /home/user/domain.com) (does't end in a slash)
define('ROOT_PATH', $_SERVER['DOCUMENT_ROOT']);
# Define where cookies may be active. ('/' means the entire domain)
define('COOKIE_PATH', '/');
# Name sessions. (needs to be alphanumeric with no periods[.]- can't be solely digits; must contain at least one letter)
define('SESSIONS_NAME', 'SiteUser');
# Get the Session Class.
require_once BASE_PATH.'modules'.DS.'Session'.DS.'Session.php';
# Check if there is a session id set the the $sesh_id variable.
$sesh_id=((isset($sesh_id)) ? $sesh_id : NULL);
# Create a new session object, thus starting a new session.
$mysession=MySession::getInstance(NULL, NULL, NULL, $sesh_id);
Login
<?php
namespace MyApp;
use Exception;
# Make sure the script is not accessed directly.
if(!defined('BASE_PATH'))
{
exit('No direct script access allowed');
}
# Get the User Class
require_once BASE_PATH.'modules'.DS.'Login'.DS.'User.php';
/**
* Class Login
*
* The Login Class is used to login in and out users as well as checking various login privileges.
*/
class Login extends User
{
/**
* processLogin
*
* Checks if the Login has been submitted and processes it.
*
* #access public
*/
public function processLogin()
{
if($this->isLoggedIn()===TRUE)
{
header("location: main.php");
die;
}
# Check if the form has been submitted.
if($_SERVER['REQUEST_METHOD']=='POST')
{
try
{
try
{
$this->setLoginSessions($this->getID(), TRUE);
header("location: main.php");
}
catch(Exception $e)
{
throw $e;
}
}
catch(Exception $e)
{
throw $e;
}
}
}
/**
* Checks if user is logged in or not. Returns TRUE if logged in, FALSE if not.
*
* #return bool
*/
public function isLoggedIn()
{
global $mysession;
$symfony_session=$mysession->symfony_session;
//if(!isset($_SESSION['user_logged_in']))
if(!$symfony_session->has('user_id'))
{
# Check if we have a cookie
if(isset($_COOKIE['cookie_id']))
{
try
{
$this->setID($_COOKIE['cookie_id']);
}
catch(Exception $e)
{
unset($_COOKIE['user_ip']);
unset($_COOKIE['athenticate']);
unset($_COOKIE['cookie_id']);
return FALSE;
}
}
else
{
return FALSE;
}
}
//elseif($_SESSION['user_logged_in']===TRUE)
if($symfony_session->get('user_logged_in')===TRUE)
{
return TRUE;
}
return FALSE;
}
/**
* Sets the login sessions.
*
* #param null $user_id
* #param null $logged_in
* #param bool $secure
* #throws Exception
*/
public function setLoginSessions($user_id=NULL, $logged_in=NULL, $secure=FALSE)
{
global $mysession;
$symfony_session=$mysession->symfony_session;
# Check if the user is logged in.
if($this->isLoggedIn()===TRUE)
{
if($user_id===NULL)
{
try
{
# Get the User's data.
$this->findUserData();
$user_id=$this->getID();
$logged_in=TRUE;
}
catch(Exception $e)
{
throw $e;
}
}
}
$symfony_session->set('user_id', $user_id);
$symfony_session->set('user_logged_in', $logged_in);
/*
# Set the User's login sessions.
$_SESSION['user_id']=$user_id;
$_SESSION['user_logged_in']=$logged_in;
*/
}
}
Session
<?php
namespace MyApp;
use Memcache;
use Symfony\Component\HttpFoundation\Session\Session as SymfonySession;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler;
/**
* Class Session
*
* The Session class is used to access and manipulate Sessions and data stored in them.
*/
class Session
{
private static $session;
private $message=FALSE;
private $sessname=FALSE;
public $symfony_session;
/**
* Session constructor.
*
* Safely calls session_start().
* Also enables sessions to span sub domains. It names the session (which is necessary for
* session_set_cookie_params() to work). If calling this class before setting.php, $sessname (the session name) AND
* $cookiepath (the path for cookies) MUST be defined.
*
* #param null $sessname
* #param null $cookiepath
* #param bool $secure
* #param null $sesh_id
*/
public function __construct($sessname=NULL, $cookiepath=NULL, $secure=FALSE, $sesh_id=NULL)
{
require_once BASE_PATH.'vendor'.DS.'autoload.php';
$memcache=new Memcache;
$memcache->connect(DOMAIN_NAME, 11211);
$storage=new NativeSessionStorage(array(), new Handler\MemcacheSessionHandler($memcache));
$symfony_session=new SymfonySession($storage);
# Check if a session ID was passed.
if($sesh_id!==NULL)
{
//session_id($sesh_id);
$symfony_session->setId($sesh_id);
}
# Is a session already started?
//if(!isset($_SESSION['s_set']))
if(!$symfony_session->has('s_set'))
{
# If we haven't been given a session name, we will give it one.
if(empty($cookiepath))
{
# Set the default cookie path be the root of the site.
$cookiepath=DS;
# Check if the cookie path was defined in settings.php.
if(defined('COOKIE_PATH'))
{
# Check if the defined path is blank.
if(COOKIE_PATH!='')
{
# If the cookie path has been defined in settings.php, we'll use that path.
$cookiepath=COOKIE_PATH;
}
}
}
//session_set_cookie_params($life, $cookiepath, '.'.DOMAIN_NAME, $secure);
/*
* Read the current save path for the session files and append our own directory to this path.
* Note: In order to make that platform independent, we need to check for the file-seperator first.
* Now we check if the directory already has been created, if not, create one.
* Then we set the new path for the session files.
*/
# Get the session save path.
$save_path=session_save_path();
# Find out if our custom_session folder exists. If not, let's make it.
if(!is_dir(BASE_PATH.'../custom_sessions'.DS.'.'))
{
mkdir(BASE_PATH.'../custom_sessions', 0755);
}
# Is our custom_sessions folder the session save path? If not, let's make it so.
if($save_path!==BASE_PATH.'../custom_sessions')
{
//session_save_path(BASE_PATH.'../custom_sessions');
# How do I set the save path in Symfony?
}
# If we haven't been given a session name, we will give it one.
if(empty($sessname))
{
# Set the default session name.
$sessname='PHPSESSID';
# Check if the session name was defined in settings.php.
if(defined('SESSIONS_NAME'))
{
# Check if the defined name is blank.
if(SESSIONS_NAME!='')
{
# If the session name has been defined in settings.php, we'll give the session that name.
$sessname=SESSIONS_NAME;
}
}
}
$storage->setOptions(array(
'cookie_domain'=>'.'.DOMAIN_NAME,
'cookie_lifetime'=>0,
'cookie_path'=>$cookiepath,
'cookie_secure'=>$secure,
'name'=>$sessname
));
//$this->setSessname($sessname);
# Name the session.
//session_name($this->getSessname());
# Session must be started before anything.
//session_start();
//$session->setName($this->getSessname());
$symfony_session->start();
# Set the s_set session so we can tell if session_start has been called already.
//$_SESSION['s_set']=1;
$symfony_session->set('s_set', 1);
}
$this->symfony_session=$symfony_session;
print_r($symfony_session);exit;
}
/**
* getSessname
*
* Returns the data member $sessname.
*
* #access public
*/
public function getSessname()
{
return $this->sessname;
}
/**
* Sets the data member $sessname. If an empty value is passed, the data member will
* be set with FALSE. Returns the set data member value.
*
* #param $sessname
* #return bool
*/
public function setSessname($sessname)
{
# Clean it up...
$sessname=trim($sessname);
# Check if the passed value is now empty.
if(empty($sessname))
{
# Explicitly set the data member to false.
$sessname=FALSE;
}
# Set the data member.
$this->sessname=$sessname;
# Return the data member after it has gone through the get method.
return $this->getSessname();
}
/**
* Gets the singleton instance of this class.
*
* #param null $sessname
* #param null $cookiepath
* #param bool $secure
* #param null $sesh_id
* #return Session
*/
public static function getInstance($sessname=NULL, $cookiepath=NULL, $secure=FALSE, $sesh_id=NULL)
{
if(!self::$session)
{
self::$session=new Session($sessname, $cookiepath, $secure, $sesh_id);
}
return self::$session;
}
}
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Session\SessionProvider;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use MyApp\Chat;
$port="8080";
# Change to this directory.
chdir(dirname(__FILE__));
# Need this for the database insert.
if(!defined('DOMAIN_NAME'))
{
define('DOMAIN_NAME', 'example.dev');
}
require_once '../../includes/lonconfig.php';
require_once '../../vendor/autoload.php';
$memcache=new Memcache;
$memcache->connect(DOMAIN_NAME, 11211);
$session=new SessionProvider(
new Chat,
new Handler\MemcacheSessionHandler($memcache)
);
$server=IoServer::factory(
new HttpServer(
new WsServer($session)
),
$port,
DOMAIN_NAME
);
$server->run();
Chat
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface
{
protected $clients=array();
public function onOpen(ConnectionInterface $conn)
{
# get the cookies
$cookies=(string)$conn->WebSocket->request->getHeader('Cookie');
# Returns only PHPSESSID (not SiteUser).
//var_dump($cookies);exit;
$this->clients[$conn->resourceId]=$conn;
echo "New connection! ({$conn->resourceId})\n";
}
/**
* #param ConnectionInterface $conn
* #param string $data
*/
public function onMessage(ConnectionInterface $conn, $data)
{
$database=$this->dbh;
$data=json_decode($data, TRUE);
if(isset($data['data']) && count($data['data'])!=0)
{
require_once BASE_PATH.'vendor'.DS.'autoload.php';
$memcache=new Memcache;
$memcache->connect(DOMAIN_NAME, 11211);
$storage=new NativeSessionStorage(array(), new Handler\MemcacheSessionHandler($memcache));
$session=new SymfonySession($storage);
$type=$data['type'];
$user_id=$conn->Session->get('user_id');
$return=NULL;
if($type=="send" && isset($data['data']['type']) && $user_name!=-1)
{
$msg=htmlspecialchars($data['data']['msg']);
$date=new DateTime;
$date->setTimezone(new DateTimeZone(TIMEZONE));
if($data['data']['type']=='text')
{
echo 'test 4';exit;
$database->query('SELECT `id`, `user_id`, `msg`, `type` FROM `chat` ORDER BY `id` DESC LIMIT 1', array());
$lastMsg=$database->statement->fetch(PDO::FETCH_OBJ);
if($lastMsg->user_id==$user_id && (strlen($lastMsg->msg)<=100 || strlen($lastMsg->msg)+strlen($msg)<=100))
{
# Append message.
$msg=$lastMsg->msg."<br/>".$msg;
$database->query('UPDATE `chat` SET `msg`=:msg, `posted`=NOW() WHERE `id`=:lastmsg', array(
':msg'=>$msg,
':lastmsg'=>$lastMsg->id
));
$return=array(
"id"=>$lastMsg->id,
"name"=>$user_name['staffname'],
"type"=>"text",
"msg"=>$msg,
"posted"=>$date->format("Y-m-d H:i:sP"),
"append"=>TRUE
);
}
else
{
$database->query('INSERT INTO `chat` (`user_id`, `msg`, `type`, `posted`) VALUES (?, ?, "text", NOW())', array(
$user_id,
$msg
));
# Get last insert ID.
$get_chat_id=$database->lastInsertId();
$return=array(
"id"=>$get_chat_id,
"name"=>$user_name['staffname'],
"type"=>"text",
"msg"=>$msg,
"posted"=>$date->format("Y-m-d H:i:sP")
);
}
}
foreach($this->clients as $client)
{
$this->send($client, "single", $return);
}
}
elseif($type=="fetch")
{
# Fetch previous messages.
$this->fetchMessages($conn, $data['data']['id']);
}
}
}
}
You shouldn't actually share that data over all parts of your application.
If you open the tutorial of Ratchet, you will find a part about pushServers.
This allows you to push to a certain channel or $user_id(in your case)
This makes you able to not save or transfer the data in the two parts and will facilitate you to have a streamlined workflow.
I personally use the pushServer in multiple channels, they are split up into:
All users online (sendBroadcast)
All users in a group (sendGroup)
All users following a tag (sendTag)
To other users(sendToUser)
I hope this already gives you an idea on how to solve your problem, otherwise feel free to ask.
Related
It's my first time to use Laravel and Redis. I understand how to get, set, etc of Redis on Terminal. But no idea how to apply Redis on Laravel application.
I have application that saves participant's information in DB with MVC pattern. and I'd like to change it to use Redis cache to make it faster(and for practice). What do I have to do? Could you explain it with code?
This is ParticipantController. 'edit' function send user to edit page, and user edit the information and push 'save', it activate 'update' function. store/updateUserInput functions are just saving data to DB nothing else.
/**
* Show the form for editing the specified participant.
*
* #param int $id
* #return View
*/
public function edit(int $id): View
{
$participant = Participant::find($id);
if(empty($participant)){
return view('errors.404');
}
return view('participants.edit', ['participant'=>$participant]);
}
/**
* Update the specified participant in storage.
*
* #param ParticipantValidation $request
* #return RedirectResponse
*/
public function update(ParticipantValidation $request): RedirectResponse
{
$participant = Participant::find($request->id);
if(empty($participant)){
return view('errors.404');
}
$detail = $request->all();
Participant::updateUserInput($detail);
return redirect()->route('participants.create', $detail['event_id'])->with('success', 'Updated!');
}
+plus I tried this code on top of 'Controller' to use sth like $redis->set('message', 'Hello world'); but there's error that they cannot find 'Predis/Autoload.php'
require 'Predis/Autoload.php';
PredisAutoloader::register();
try {
$redis = new PredisClient();
}
catch (Exception $e) {
die($e->getMessage());
}
You can use the Cache facade
In your .env file, you must add CACHE_DRIVER=redis
Then whenever you want to get an instance of Participant:
$participant = null;
$key ="Participant".$id;
if(Cache::has($key)//get participant from cache
$participant = Cache::get($key);
else{//get participant and cache for 3 minutes
$participant = Participant::find($id);
$seconds = 180;
Cache::set($key, $participant, $seconds);
}
On Owncloud 8.1 using the owncloud command line, I create a new test app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 8
The app is working, I can add it in the owncloud control panel.
Now I'd like to write to a file, so I use one example from the owncloud documentation:
https://doc.owncloud.org/server/8.1/developer_manual/app/filesystem.html
[Edit] I started over and now, I don't know if I omitted something, but "myapp" comes with no "application.php" file.
So I create it at /var/www/core/apps/myapp/appinfo/application.php :
<?php
namespace OCA\MyApp\AppInfo;
use \OCP\AppFramework\App;
use \OCA\MyApp\Storage\AuthorStorage;
class Application extends App {
public function __construct(array $urlParams=array()){
parent::__construct('myapp', $urlParams);
$container = $this->getContainer();
/**
* Storage Layer
*/
$container->registerService('AuthorStorage', function($c) {
return new AuthorStorage($c->query('RootStorage'));
});
$container->registerService('RootStorage', function($c) {
return $c->query('ServerContainer')->getRootFolder();
});
}
}
Then I create a file called /var/www/core/apps/myapp/storage/AuthorStorage.php with:
<?php
namespace OCA\MyApp\Storage;
class AuthorStorage {
private $storage;
public function __construct($storage){
$this->storage = $storage;
}
public function writeTxt($content) {
// check if file exists and write to it if possible
try {
try {
$file = $this->storage->get('/myfile.txt');
} catch(\OCP\Files\NotFoundException $e) {
$this->storage->touch('/myfile.txt');
$file = $this->storage->get('/myfile.txt');
}
// the id can be accessed by $file->getId();
$file->putContent($content);
} catch(\OCP\Files\NotPermittedException $e) {
// you have to create this exception by yourself ;)
throw new StorageException('Cant write to file');
}
}
}
The sample app already gives me a route to the index function in the pagecontroller.php
['name' => 'page#index', 'url' => '/', 'verb' => 'GET']
How do I call the function "writeTxt" from there?
Based on http://php.net/manual/en/language.oop5.basic.php
I tried:
use \OCA\MyApp\Storage\AuthorStorage;
and
public function index() {
//added part
$a = new AuthorStorage();
$a->writeTxt('test');
//original part
$params = ['user' => $this->userId];
return new TemplateResponse('myapp', 'main', $params); //templates/main.php
}
After running I get a "Class 'OCA\MyApp\Storage\AuthorStorage' not found at /var/www/core/apps/myapp/controller/pagecontroller.php#44"
Even with the help of use \OCA\MyApp\Storage\AuthorStorage; ( ClassNotFoundException: Attempted to load class... Symfony ) it doesn't seem to help.
Thanks
Time has gone by, so I'm posting an answer to my question for owncloud 9.
Here are the steps to a basic script with read, write, copy file ability.
"application.php" has definitively been removed from the example. It was not a bug.
Following:
https://doc.owncloud.org/server/9.0/developer_manual/app/startapp.html
Generate the demo "MyApp" app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 9
Edit the file myapp/controller/pagecontroller.php
<?php
/**
* ownCloud - myapp
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* #author Your Name <mail#example.com>
* #copyright Your Name 2016
*/
namespace OCA\MyApp\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Controller;
use OCP\Files\IRootFolder;
use OC\Files\Storage\Temporary;
class PageController extends Controller {
private $userId;
private $storage;
private $userstorage;
public function __construct($AppName, IRequest $request, IRootFolder $storage, $UserId){
parent::__construct($AppName, $request);
$this->storage = $storage;
$this->userId = $UserId;
$this->userstorage = $this->storage->get($this->userId.'/files/');
}
/**
* CAUTION: the #Stuff turns off security checks; for this page no admin is
* required and no CSRF check. If you don't know what CSRF is, read
* it up in the docs or you might create a security hole. This is
* basically the only required method to add this exemption, don't
* add it to any other method if you don't exactly know what it does
*
* #NoAdminRequired
* #NoCSRFRequired
*/
public function index() {
$listedudossier = $this->userstorage->getDirectoryListing();
//list all items in the root directory
//and copies the files in an directory called old
//the directory "old" is not script created
foreach ($listedudossier as $value) {
if ( $value->getType() == 'file' ){
$value->copy($this->userId.'/files/old/'.$value->getName());
//also works
//$value->copy($this->userstorage->getPath().'/old/'.$value->getName());
}
}
$params = ['listedudossier' => $listedudossier ];
return new TemplateResponse('myapp', 'main', $params); // templates/main.php
}
/**
* Simply method that posts back the payload of the request
* #NoAdminRequired
*/
public function doEcho($echo) {
//creates a file
$this->userstorage->newFile('myfile2.txt');
//opens a file, adds inputbox content and saves the file
$file = $this->userstorage->get('myfile.txt');
$contenu = $file->getContent();
$file->putContent($contenu.$echo);
return new DataResponse(['echo' => $echo]);
}
}
You also need to edit the myapp/templates/part.content.php
<p>Hello World <?php p($_['user']) ?></p>
<p><button id="hello">click me</button></p>
<p><textarea id="echo-content">
Send this as ajax
</textarea></p>
<p><button id="echo">Send ajax request</button></p>
Ajax response: <div id="echo-result"></div>
<p>listedudossier:<p> <?php
foreach ($_['listedudossier'] as $file) {
echo "type:".$file->getType();
echo "<p>";
echo "nom:".$file->getName();
echo "<p>";
echo "modif:".$file->getMTime();
echo "<p>";
}
From here you can test the code in a development environment:
https://github.com/owncloud/ocdev/blob/master/README.rst#installation
I've successfully used APNS-PHP to send PNs - it's great!
However, I'm a little stuck on how to add it to a Code Igniter project
(inside a controller that will be called from command-line).
Calling:
require_once APPPATH.'/third_party/ApnsPHP/Autoload.php';
Results in errors:
Fatal error: Uncaught exception 'Exception' with message 'Class file
'XXXXXXX/application/third_party/CI/DB/mysql/result.php' does not
exists' in XXXXXXX/application/third_party/ApnsPHP/Autoload.php:49
I'm assuming it's some kind of autoloading conflict? But I'm not
really sure!
Any help would be brilliant - I've trawled Google without much luck!
Here's the line I've being trying to use inside the function:
require_once APPPATH.'/third_party/ApnsPHP/Autoload.php';
Here's the __autoload function I've added for loading Ion Auth's libs:
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
if (file_exists($file = APPPATH.'core/'.$class.EXT))
{
include $file;
}
else if (file_exists($file = APPPATH.'libraries/'.$class.EXT))
{
include $file;
}
else if (file_exists($file = APPPATH.'core/base_controllers/'.$class.EXT))
{
include $file;
}
}
}
With no other changes to the library, this works for me. It sidesteps CI a bit, but still allows you to load in APNS-PHP as a model:
<?php
if(!defined('BASEPATH')) exit('No direct script access allowed');
class Notification_model extends CI_Model {
protected $apnsDir = '';
// -----------------------------------------------
/**
* Setup some basic stuffs
* #param void
* #return void
* #access public
*/
public function __construct() {
parent::__construct();
/* get all the APNS files */
$this->apnsDir = $_SERVER['DOCUMENT_ROOT'].'/application/third_party/ApnsPHP/';
$this->_apns_req();
return;
} /* /__construct() */
// -----------------------------------------------
/**
* Will send the actual iOS notification to the user
* #param $token string iOS device token
* #param $msg string
* #param $attrs array Key/value pairs to be sent as meta with APN
* #return void
* #access public
*/
private function send_ios($token=null, $msg=null, $attrs=array()) {
if(!$token || !$msg) return;
// Instantiate a new ApnsPHP_Push object
$push = new ApnsPHP_Push(
ApnsPHP_Abstract::ENVIRONMENT_SANDBOX,
$this->apnsDir.'SSL/server_certificates_bundle_sandbox.pem'
);
// Set the Provider Certificate passphrase
// $push->setProviderCertificatePassphrase('tablecan29');
// Set the Root Certificate Autority to verify the Apple remote peer
$push->setRootCertificationAuthority($this->apnsDir.'SSL/entrust_root_certification_authority.pem');
// Connect to the Apple Push Notification Service
$push->connect();
// Instantiate a new Message with a single recipient
$message = new ApnsPHP_Message($token);
// Set a custom identifier. To get back this identifier use the getCustomIdentifier() method
// over a ApnsPHP_Message object retrieved with the getErrors() message.
$message->setCustomIdentifier("Message-Badge-3");
// Set badge icon to "3"
// $message->setBadge(0);
// Set a simple welcome text
$message->setText($msg);
// Play the default sound
$message->setSound();
// Set custom properties
if( is_array($attrs) && count($attrs) )
{
foreach( $attrs as $attr_key => $attr_val )
{
$message->setCustomProperty($attr_key, $attr_val);
}
}
// Set the expiry value - in seconds
$message->setExpiry(120);
// Add the message to the message queue
$push->add($message);
// Send all messages in the message queue
$push->send();
// Disconnect from the Apple Push Notification Service
$push->disconnect();
// Examine the error message container
// $aErrorQueue = $push->getErrors();
// if (!empty($aErrorQueue)) {
// var_dump($aErrorQueue);
// }
return TRUE;
} /* /send_ios() */
// -----------------------------------------------
private function _apns_req() {
require_once $this->apnsDir.'Abstract.php';
require_once $this->apnsDir.'Exception.php';
require_once $this->apnsDir.'Feedback.php';
require_once $this->apnsDir.'Message.php';
require_once $this->apnsDir.'Log/Interface.php';
require_once $this->apnsDir.'Log/Embedded.php';
require_once $this->apnsDir.'Message/Custom.php';
require_once $this->apnsDir.'Message/Exception.php';
require_once $this->apnsDir.'Push.php';
require_once $this->apnsDir.'Push/Exception.php';
require_once $this->apnsDir.'Push/Server.php';
require_once $this->apnsDir.'Push/Server/Exception.php';
return;
} /* /_apns_req() */
} /* /Notification_model{} */
/* End of file notification_model.php */
/* Location: ./application/models/notification_model.php */
Example usage:
$this->load->model('notification_model');
$this->notification_model->send_ios($token, 'Test Message', array('custom_var' => 'val'));
Is there a way to restore session, knowing its ID, in Kohana 2.x?
From the Kohana 2.* repository: Line 113 of system/libraries/Session.php. Session::instance allows for an ID to be passed in.
/**
* Singleton instance of Session.
*
* ##### Example
*
* // This is the idiomatic and preferred method of starting a session
* $session = Session::instance();
*
* #param string Force a specific session_id
*/
public static function instance($session_id = NULL)
{
if (Session::$instance == NULL)
{
// Create a new instance
new Session($session_id);
}
elseif( ! is_null($session_id) AND $session_id != session_id() )
{
throw new Kohana_Exception('A session (SID: :session:) is already open, cannot open the specified session (SID: :new_session:).', array(':session:' => session_id(), ':new_session:' => $session_id));
}
return Session::$instance;
}
I want to store all my sessions in a DB and have read up on this and implemented the following class:
<?php
/**
* This class handles users sessions and stores the session in the DB rather than in a file. This way stops any
* shared host security problems that could potentially happen.
*/
class sessionHandler {
/**
* Initial constructor which takes the database object as a param, to do all the database stuff
* #param object $db The datase object
*/
public function __construct ($db) {
$this->db = $db;
$this->setHandler();
}
function setHandler() {
session_set_save_handler(array(&$this, "open"),
array(&$this, "close"),
array(&$this, "read"),
array(&$this, "write"),
array(&$this, "destroy"),
array(&$this, "clean")
);
}
/**
* Initiate a database object if necessary
*/
function open() {
$this->db->connect();
}
/**
* Write session id and data to the database
* #param string $id The hashed 32 char session id, unique to a user
* #param string $data Serialized session array from the unique session
* #return id The newly inserted ID of the database
*/
function write($id, $data) {
$access = time();
$dateAdded = date("Y-m-d G:i:s");
$this->db->wrapper->where(array("sessionId"=>$id));
$this->db->query($this->db->wrapper->delete(__CLASS__));
//fopen a file and store this in it that way we can debug
$query = $this->db->wrapper->insert(__CLASS__, array("sessionId"=>$id,"dateAdded"=>$dateAdded,"sessionData"=>$data));
$this->db->query($query);
return $this->db->insertId();
}
/**
* Retrieve the session data for a given session id
* #param string $id The hashed 32 char session id, unique to a user
* #return string The session data found for the given session id
*/
function read($id) {
$id = $this->db->wrapper->escape($id);
$row = $this->db->fetch(1, $this->db->wrapper->get_where(__CLASS__,array("sessionId"=>$id)), array(),false);
if ($row) {
return $row['data'];
}
return "";
}
/**
* Delete a session from the database by its unique session id
* #param string $id The hashed 32 char session id, unique to a user
* #return integer The number of deleted rows - should only ever be 1
*/
function destroy($id) {
$id = $this->db->wrapper->escape($id);
$this->db->wrapper->where(array("sessionId"=>$id));
$this->db->query($this->db->wrapper->delete(__CLASS__));
return $this->db->affectedRows();
}
/**
* Garage collector which deletes old records in the database, delete sessions that have expired. This is
* determined by the session.gc_maxlifetime variable in the php.ini
* #param integer $max The maximum number of seconds allowed before a session is to be considered expired
* #return integer The number of deleted rows
*/
function clean($max) {
$old = time() - $max;
$old = $this->db->wrapper->escape($old);
$this->db->wrapper->where(array("access"=>$old), "<");
$this->db->query($this->db->wrapper->delete(__CLASS__));
return $this->db->affectedRows();
}
/**
* Close the database connection once a read / write has been complete
*/
function close() {
$this->db->close();
}
/**
* End the current session and store session data.
*/
public function __destruct(){
session_write_close();
}
}
As you can see in my code, i pass the DB object into the class as a param. My bootstrap file is as follows:
$db = mogDB::init();
$sh = new sessionHandler($db);
session_start();
I have used a few of my own classes here so MogDB:init() basically creates a database connection with the right credentials. The wrapper stuff is basically so i dont have to type out sql query after sql query (me being a bit lazy i guess).
But the problem i get is this in my php error log:
08-Apr-2010 17:40:31] PHP Warning: mysql_insert_id(): 11 is not a valid MySQL-Link resource in /library/mysql.php on line 69
I have debugged this as much as i can and it seems that when it tries to write the session to the DB, it is failing. I have managed to save the query to a file and that imports fine into the database via phpmyadmin, so its not the query thats the problem.
line 69 in mysql.php is as follows:
68. public function insertId() {
69. return mysql_insert_id($this->id);
70. }
Any help would be much appreciated
Thanks
After you include the contents of the file /library/mysql.php around line 69 so we can see what is happening there, I am guessing that a small bit of your code is asking for a database handle back to call mysql_insert_id on, and instead, your db api is giving back the actual insertID already...