php7 - Custom SessionHandler raises session_write_close() warning - php

I upgraded my project from php5.6 to php7.0 and got from time to time a php warning about session_write_close(), showing me the correct path to my temp folder.
My project uses a custom database session handler which worked perfectly with the older php version.
The error is as follows:
Warning: Unknown: Failed to write session data (user). Please verify
that the current setting of session.save_path is correct (C:\my\path)
in Unknown on line 0
Here is my write() fucntion:
/**
* #param string $id
* #param string $data
* #return bool
* #throws Zend_Db_Adapter_Exception
*/
public function write($id, $data)
{
$dateTime = date('Y-m-d H:i:s');
$newDateTime = date('Y-m-d H:i:s', strtotime($dateTime . sprintf(' + %s seconds', $this->getMaxLifetime())));
$sessionValues = array("id" => $id, "expires_at" => $newDateTime, "session_data" => $data);
$sel = new Zend_Db_Select($this->_zdb);
$sel->from(self::TABLE_NAME, array('id'))
->where('id = ?', $id);
$sessionExists = (bool)$this->_zdb->fetchOne($sel);
if($sessionExists) {
$result = $this->_zdb->update(self::TABLE_NAME, $sessionValues, array('id = ?' => $id));
} else {
$result = $this->_zdb->insert(self::TABLE_NAME, $sessionValues);
}
if($result) {
return true;
} else {
return false;
}
}
Any ideas what I can do about it?

Ok, finally I found the solution:
My database adapter inside my custom session handler returns 0 on an update on the session table which doesn't update any values.
I returned the result of my query in the write()-function.
This guy here explained the problem.
The SessionHandlerInterface::write() function raises this warning in case it returns false.
Maybe this helps somebody else as well.

Related

PHPUnit Test (Lagacy Route, Legacy Container) - test whether user is already created

I am using PHP, PHP Legacy Router and PHP Legacy Container.
I am using also PHPUnit test
I am trying to make a correct PHPUnit test, however, I am a begginer and I don`t know whether my code is ok or it is wrong.
In my NewUserService class I write 2 functions to get all emails and if the email is already existed in the db to return an error that user is created already.
My problem is how to test this functionality trough PHPUnit tests in my NewUserServiceTest
This is my functionality to test whether the user is already created
public function getAllUsersEmails()
{
$sql ="SELECT `email` FROM users";
$stmt = $this->container->get('db')->prepare($sql);
$stmt->execute();
if ($stmt->errorCode() != '00000') throw new Exception(sprintf(("Database error (%s): %s"), $stmt->errorCode(), $stmt->errorInfo()[2]));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* #throws Exception
*/
private function repeatingEmailAddress($requestObj){
$allUsersEmails = NewUserService::getAllUsersEmails();
$allUsersEmailsValues = [];
foreach ($allUsersEmails as $value){
$allUsersEmailsValues[]=$value['email'];
}
if(in_array($requestObj['email'], $allUsersEmailsValues)){
throw new Exception("A user with that email is already created.", 400);
}
This is the unit test:
private function repeatingUserEmail(): array
{
$request = $this->createStub(ServerRequestInterface::class);
$requestJsonPayload = '{"email": "mj#hph.io", "role": 2, "first": "Griffin", "last": "Mitchell"}';
$requestStream = fopen('php://memory', 'r+');
fwrite($requestStream, $requestJsonPayload);
rewind($requestStream);
$request->method('getBody')->willReturn(new Stream($requestStream));
$routeArgs = ['id' => 4];
/* <container with user> */
$container = $this->getStandardContainer();
$user = $this->createMock(User::class);
$user->id = '1';
$user->role = '1';
$user->parent_entity = '11';
$user->email='mj#hph.io';
$container->add('current_user', $user);
$response = ['error' => 'A user with that email is already created.'];
$responseJsonPayload = json_encode($response);
$responseStream = fopen('php://memory', 'r+');
fwrite($responseStream, $responseJsonPayload);
rewind($responseStream);
$expectedResponse = $this->createMock(ResponseInterface::class);
$expectedResponse->method('getStatusCode')->willReturn(400);
$expectedResponse->method('getBody')->willReturn(new Stream($responseStream));
return [$request, $routeArgs, $container, $expectedResponse];
}
Is it correct? How should be done in a correct way?
First of all i suggest to make a isEmailExists($email) method that will search this specific email in the database and return bollean response (true/false). So you don't have to pull millions of emails from database and then loop through millions of rows and in the end you just throw an error.
Back to the test. I suggest to use the expectException assertion that you can find in the documentation
You can 1)add one row in you database and then try to pass the same email that will throw this error or 2)partial mock the
isEmailExists($email) to return true and throw your exception (without hit the database at all)

Why success is not being returned in my PHP WSDL (Zf2)

I used these two resources as launching pad for my creation of a WSDL endpoint server.
https://odan.github.io/2017/11/20/implementing-a-soap-api-with-php-7.html
https://www.youtube.com/watch?v=e_7jDqN2A-Y&t=799s
By combining these two I was able to come up with a hybrid system that works. My issue that I am trying resolve right now is getting a response back from the api.php/endpoint server.
In the odan git example, it worked to the letter. But once I made changes to the code that requires objects. I started getting errors.
PHP Notice: Trying to get property of non-object
Here is a portion of the server code.
class wenoError
{
public $response = "Sucess";
public static function authenticate($header_params)
{
if($header_params->username == 'WEX' && $header_params->password == 'WEX1') return true;
else throw new SOAPFault('Wrong user/pass combination', 601);
}
/**
* #param string $payload
* #return string $delivery
*/
public function receivePayload($payload)
{
$xml = base64_decode($payload);
$fileName = 'message-'.rand().'.xml';
$file = file_put_contents('messages/'.$fileName, $xml);
$xml2json = simplexml_load_string($xml);
$jsonOut = json_encode($xml2json);
$arrayJson = json_decode($jsonOut, TRUE);
//$seeArray = print_r($arrayJson, true);
//file_put_contents('messages/converted-'.$fileName.'.json', $arrayJson['Header']['MessageID']);
$response = "Success";
return $response;
}
}
$serverUrl = "https://localhost/WenoErrors/api.php";
$options = [
'uri' => $serverUrl,
];
$server = new Zend\Soap\Server('wsdl', $options);
if (isset($_GET['wsdl'])) {
$soapAutoDiscover = new \Zend\Soap\AutoDiscover(new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence());
$soapAutoDiscover->setBindingStyle(array('style' => 'document'));
$soapAutoDiscover->setOperationBodyStyle(array('use' => 'literal'));
$soapAutoDiscover->setClass('wenoError');
$soapAutoDiscover->setUri($serverUrl);
header("Content-Type: text/xml");
echo $soapAutoDiscover->generate()->toXml();
} else {
$soap = new \Zend\Soap\Server($serverUrl . '?wsdl');
$soap->setObject(new \Zend\Soap\Server\DocumentLiteralWrapper(new wenoError()));
$soap->handle();
}
What I don't understand is the error message of $response being a non-object. According to the PHP manual https://www.php.net/manual/en/language.oop5.properties.php
The property is set correctly at the top of the class, the property is declared and a value us set.
What went wrong?
UPDATE:
Adding the client code.
$client = new Zend\Soap\Client('https://localhost/WenoErrors/api.php?wsdl');
$delivery = $client->call('receivePayload',[['payload' => $message]]);
Dumping client yields:
C:\eRxGateway\www\apa\WenoErrors\clientapi.php:55:
object(client)[3]
public 'delivery' => null
UPDATE:
What finally worked for me was this change.
First change:
$server = new Zend\Soap\Server('wsdl', $options);
$server = new Zend\Soap\Server(null, $options);
Your code seems to work fine for me. Though, I am getting a different result then yours as below:
$client = new Zend\Soap\Client('http://localhost/test/api.php?wsdl');
$message = ' -> Hello World';
$delivery = $client->call('receivePayload',[['payload' => $message]]);
var_dump($delivery);
object(stdClass)#4 (1) {
["receivePayloadResult"]=>
string(7) "Success"
}
Step 1
Please try to remove all the '/tmp/wsdl-****' files from your /tmp directory. You seem to be on windows, so instead of /tmp it might be something else like C:\Windows\Temp. You can easily find which directory by going into your php.ini file and looking for the below directive.
soap.wsdl_cache_dir="/tmp"
Step 2
Also, for developing and testing purposes always put the below ini directive at the start of your client php file, which in your case is clientapi.php file.
ini_set("soap.wsdl_cache_enabled", 0);
You shouldn't be required to put this directive at the start of the server(api.php) file, but you can if the above still does not work for you.

Joomla 3.3 - How to store user password?

i'm trying to store user password in a plugin using joomla 3.3.6.
According to Joomla Documentation : https://docs.joomla.org/Inserting,_Updating_and_Removing_data_using_JDatabase
I created the following function :
/**
*
* Update Password
*
* #param unknown $idUser
* #param unknown $password
*/
public function updateUserPassword($idUser, $password) {
// Create a new query object.
$query = $this->db->getQuery ( true );
$value = JUserHelper::hashPassword($password);
// Prepare the insert query.
$query->update('#__users')
->set('password = ' . $this->db->quote($value))
->where('id = ' . $idUser);
// Set the query using our newly populated query object and execute it.
$this->db->setQuery ($query);
$updateResult = $this->db->execute ();
if ($updateResult == false) {
$errorMsg = $this->db->getErrorMsg ();
var_dump($errorMsg);
} else {
echo "Update Done";
}
}
This code is executed without any error or warning but the user record in table users remains unchanged.
$query value is :
UPDATE #__users
SET password = '$2y$10$hO2MfDLfG5ICy2yhZWXZG.GCQ89vYw26KHVisXuuD8baRU9WtuDR.'
WHERE id = 192
$query looks fine. Executing the query in mysqlworkbench by replacing #__ with my custom db prefix returns ok and i can see changes in db.
However the php code doesn't work.
Anyone have a clue about this ?
Dev.
EDIT
Code Change : Adding error handling in execute statement.
The message "Update Done" is printed.
From your code snippet, I don't see how you've determined that the code is executing without any error.
From the Joomla documentation
https://api.joomla.org/cms-3/classes/JDatabaseDriver.html#method_execute
your execute statement should have a return value of either a cursor or false.
$updateResult = $this->db->execute();
if($updateResult == false) {
$errorMsg = $this->db->getErrorMsg();
//display this in your method of choice
}
Depending on your server, there may also be an web server error log entry. On my LAMP development machine, it's in /var/log/apache2/error_log
Alternate method to modify a Joomla table record
$user_record = new stdClass();
$user_record->id = $idUser;
$user_record->password = $password;
$result = JFactory::getDbo()->insertObject('#__users', $user_record, $idUser);

phpMyAdmin Fatal error: Call to undefined function __()

Server running RHEL 7 and PHP 5.4.16. When I try to open /phpMyAdmin in my browser, I'm given the error:
Fatal error: Call to undefined function __() in /usr/share/phpMyAdmin/libraries/core.lib.php on line 242
Call Stack
# Time Memory Function Location
1 0.0008 348000 {main}( ) ../index.php:0
2 0.0018 503144 require_once( '/usr/share/phpMyAdmin/libraries/common.inc.php' ) ../index.php:12
3 0.0252 4224464 PMA_Config->__construct( ) ../common.inc.php:304
4 0.0252 4224712 PMA_Config->load( ) ../Config.class.php:100
5 0.0265 4309888 PMA_Config->checkConfigSource( ) ../Config.class.php:849
6 0.0265 4311088 PMA_fatalError( ) ../Config.class.php:1169
I believe I've installed all required libraries and that apache has the proper permissions for the session.save_path directory, which were the issues previous times that this question had been asked. See: Call to undefined function __() error - phpMyAdmin
Can someone give me a hint based on that call stack?
Here are the functions from the lines that the stack trace references, with the relevant line written in the left margin:
core.lib.php at line 242:
/**
* displays the given error message on phpMyAdmin error page in foreign language,
* ends script execution and closes session
*
* loads language file if not loaded already
*
* #param string $error_message the error message or named error message
* #param string|array $message_args arguments applied to $error_message
* #param boolean $delete_session whether to delete session cookie
*
* #return void
*/
function PMA_fatalError(
$error_message, $message_args = null, $delete_session = true
) {
/* Use format string if applicable */
if (is_string($message_args)) {
$error_message = sprintf($error_message, $message_args);
} elseif (is_array($message_args)) {
$error_message = vsprintf($error_message, $message_args);
}
if ($GLOBALS['is_ajax_request']) {
$response = PMA_Response::getInstance();
$response->isSuccess(false);
$response->addJSON('message', PMA_Message::error($error_message));
} else {
$error_message = strtr($error_message, array('<br />' => '[br]'));
/* Load gettext for fatal errors */
if (!function_exists('__')) {
// It is possible that PMA_fatalError() is called before including
// vendor_config.php which defines GETTEXT_INC. See bug #4557
if (defined(GETTEXT_INC)) {
include_once GETTEXT_INC;
} else {
include_once './libraries/php-gettext/gettext.inc';
}
}
// these variables are used in the included file libraries/error.inc.php
242 $error_header = __('Error');
$lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1];
$dir = $GLOBALS['text_dir'];
// on fatal errors it cannot hurt to always delete the current session
if ($delete_session
&& isset($GLOBALS['session_name'])
&& isset($_COOKIE[$GLOBALS['session_name']])
) {
$GLOBALS['PMA_Config']->removeCookie($GLOBALS['session_name']);
}
// Displays the error message
include './libraries/error.inc.php';
}
if (! defined('TESTSUITE')) {
exit;
}
}
common.inc.php at line 304:
304 $GLOBALS['PMA_Config'] = new PMA_Config(CONFIG_FILE);
if (!defined('PMA_MINIMUM_COMMON')) {
$GLOBALS['PMA_Config']->checkPmaAbsoluteUri();
}
Config.class.php at line 100:
/**
* constructor
*
* #param string $source source to read config from
*/
function __construct($source = null)
{
$this->settings = array();
// functions need to refresh in case of config file changed goes in
// PMA_Config::load()
100 $this->load($source);
// other settings, independent from config file, comes in
$this->checkSystem();
$this->isHttps();
$this->base_settings = $this->settings;
}
Config.class.php at line 849:
/**
* loads configuration from $source, usually the config file
* should be called on object creation
*
* #param string $source config file
*
* #return bool
*/
function load($source = null)
{
$this->loadDefaults();
if (null !== $source) {
$this->setSource($source);
}
/**
* We check and set the font size at this point, to make the font size
* selector work also for users without a config.inc.php
*/
$this->checkFontsize();
if (! $this->checkConfigSource()) {
849 return false;
}
Config.class.php at line 1169:
/**
* check config source
*
* #return boolean whether source is valid or not
*/
function checkConfigSource()
{
if (! $this->getSource()) {
// no configuration file set at all
return false;
}
if (! file_exists($this->getSource())) {
$this->source_mtime = 0;
return false;
}
if (! is_readable($this->getSource())) {
// manually check if file is readable
// might be bug #3059806 Supporting running from CIFS/Samba shares
$contents = false;
$handle = #fopen($this->getSource(), 'r');
if ($handle !== false) {
$contents = #fread($handle, 1); // reading 1 byte is enough to test
#fclose($handle);
}
if ($contents === false) {
$this->source_mtime = 0;
PMA_fatalError(
sprintf(
function_exists('__')
? __('Existing configuration file (%s) is not readable.')
: 'Existing configuration file (%s) is not readable.',
$this->getSource()
)
1169 );
return false;
}
}
return true;
}
The problem was the wrong permissions for the /etc/phpMyAdmin directory. The web server user, apache, had proper permissions for the session.save_path directory, but apache couldn't read from my config.inc.php file. Changing the owner of /etc/phpMyAdmin to the apache user and changing the permissions to 755 solved the problem.
Looking at the checkConfigSource() function in Config.class.php led me to believe that if the problem was with accessing the configuration file then I would have received the error 'Existing configuration file (%s) is not readable.' instead of Call to undefined function __() Does anyone know why that wasn't the case?
This was a pretty basic problem/solution, but unless someone suggests otherwise I think I'll leave it up since this exact problem/solution isn't addressed in other discussions of the Fatal error: Call to undefined function __() in /usr/share/phpMyAdmin/libraries/core.lib.php error when trying to start phpMyAdmin after installation.
Had the same Error message from phpMyAdmin ::
FastCGI sent in stderr: "PHP message: PHP Fatal error: Call to undefined function __() in /usr/share/phpMyAdmin/libraries/core.lib.php on line 245" while reading response header from upstream, client:
Solution that worked on my Fedora 22 server x86_64 using nginx :
changing the owner and the group identifier from root:apache on the file /var/lib/php/session
to root:nginx
using the command sudo chown -Rfv root:nginx /var/lib/php/session.
If phpmyadmin was working fine and then suddenly stops working for no reason with a bizarre and useless error message, you might try deleting your php sessions.
rm -rf /var/lib/php/sessions/*
The exact location may very depending on OS and version, and this will delete all active sessions, not just yours, but it can fix some "suddenly stopped working" issues when you haven't changed anything and it was working fine before.
For me it was different issue. I had given 777 permissions to phpMyAdmin forlder. When I changed it to 755, it worked fine.
Hope this will help someone.
Error "The connection was reset" File:
/usr/share/phpmyadmin/libraries/common.inc.php
search:
$GLOBALS['PMA_Config'] = new PMA_Config(CONFIG_FILE);<br>
replace with:
$GLOBALS['PMA_Config'] = new PMA_Config();

Joomla PHP error within page content

Warning: Parameter 3 to showBlogSection() expected to be a reference, value given in /home/smartsta/public_html/includes/Cache/Lite/Function.php on line 100
I'm getting the above error displaying within my content areas on my Joomla site all a sudden, any suggestions?
Update: No such luck finding access to defined file and directory within godaddy ftp file directory, ftp, or Joomal C-panel.
Within FTP, I cannot find access to this particular file to investigate what is on line 100.
Within the Joomla panel, in Global Configurations, I was able to toggle 'error message' to none for atleast this error to be hidden. Within the cache directory I do not see any options to get into the folder, though it displays.
I also see this at the bottom of that c-panel screen, but just links to a joomla help site, and within the fields I do not see described area to toggle 'ON or OFF'
"Following PHP Server Settings are not optimal for Security and it is recommended to change them:
PHP register_globals setting is ON instead of OFF
"
Update2!:
I've found the file in question, below is the code. Line 100 only states:
global $$object_123456789;
application/x-httpd-php Function.php
PHP script text
<?php
/**
* This class extends Cache_Lite and can be used to cache the result and output of functions/methods
*
* This class is completly inspired from Sebastian Bergmann's
* PEAR/Cache_Function class. This is only an adaptation to
* Cache_Lite
*
* There are some examples in the 'docs/examples' file
* Technical choices are described in the 'docs/technical' file
*
* #package Cache_Lite
* #version $Id: Function.php 47 2005-09-15 02:55:27Z rhuk $
* #author Sebastian BERGMANN <sb#sebastian-bergmann.de>
* #author Fabien MARTY <fab#php.net>
*/
// no direct access
defined( '_VALID_MOS' ) or die( 'Restricted access' );
require_once( $mosConfig_absolute_path . '/includes/Cache/Lite.php' );
class Cache_Lite_Function extends Cache_Lite
{
// --- Private properties ---
/**
* Default cache group for function caching
*
* #var string $_defaultGroup
*/
var $_defaultGroup = 'Cache_Lite_Function';
// --- Public methods ----
/**
* Constructor
*
* $options is an assoc. To have a look at availables options,
* see the constructor of the Cache_Lite class in 'Cache_Lite.php'
*
* Comparing to Cache_Lite constructor, there is another option :
* $options = array(
* (...) see Cache_Lite constructor
* 'defaultGroup' => default cache group for function caching (string)
* );
*
* #param array $options options
* #access public
*/
function Cache_Lite_Function($options = array(NULL))
{
if (isset($options['defaultGroup'])) {
$this->_defaultGroup = $options['defaultGroup'];
}
$this->Cache_Lite($options);
}
/**
* Calls a cacheable function or method (or not if there is already a cache for it)
*
* Arguments of this method are read with func_get_args. So it doesn't appear
* in the function definition. Synopsis :
* call('functionName', $arg1, $arg2, ...)
* (arg1, arg2... are arguments of 'functionName')
*
* #return mixed result of the function/method
* #access public
*/
function call()
{
$arguments = func_get_args();
$id = serialize($arguments); // Generate a cache id
if (!$this->_fileNameProtection) {
$id = md5($id);
// if fileNameProtection is set to false, then the id has to be hashed
// because it's a very bad file name in most cases
}
$data = $this->get($id, $this->_defaultGroup);
if ($data !== false) {
$array = unserialize($data);
$output = $array['output'];
$result = $array['result'];
} else {
ob_start();
ob_implicit_flush(false);
$target = array_shift($arguments);
if (strstr($target, '::')) { // classname::staticMethod
list($class, $method) = explode('::', $target);
$result = call_user_func_array(array($class, $method), $arguments);
} else if (strstr($target, '->')) { // object->method
// use a stupid name ($objet_123456789 because) of problems when the object
// name is the same as this var name
list($object_123456789, $method) = explode('->', $target);
global $$object_123456789;
$result = call_user_func_array(array($$object_123456789, $method), $arguments);
} else { // function
$result = call_user_func_array($target, $arguments);
}
$output = ob_get_contents();
ob_end_clean();
$array['output'] = $output;
$array['result'] = $result;
$this->save(serialize($array), $id, $this->_defaultGroup);
}
echo($output);
return $result;
}
}
?>
It is not exactly an error. It is a warning.
Suddenly? Perhaps you have upgraded/updated your PHP version. Or changed PHP configuration to "strict mode".
The message "expected to be a reference, value given" means the called function expected to receive a reference, not a value. Look:
$something = 9;
show_section($something);
// here you are passing a variable
// this will be accepted as a reference
show_section(9);
// here you are NOT passing a reference
// here you are passing a VALUE
When you pass "by reference", the function can change the variable value... in the example above:
function show_section(&$parameter) {
$parameter = 'changed!';
}
Note the ampersand symbol & before the $parameter - this is how we specify a function requires a REFERENCE.
AFTER the function call, in the example above, the variable $something value will be the changed! string.
The line throwing the error is NOT the "global" one. It is the next:
$result = call_user_func_array(array($$object_123456789, $method), $arguments);
The problem here is that the function is being called indirectly by using the "call_user_func_array" function.
A solution would be transforming all arguments into references. Suggestion:
foreach ($arguments as $count => $value)
{
$param = 'param' . $count;
$$param = $value;
$arguments[$count] = &$$param;
}
Put the code above in the beginning of the call function, right after the following line:
$id = serialize($arguments);
Give this a try!

Categories