Welcome Guest, Not a member yet? Register   Sign In
CI 3.1.3 upgrade from 3.1.2 does not allow database sessions to work (PHP 5.5)
#1

(This post was last modified: 01-10-2017, 11:38 AM by skunkbad. Edit Reason: Showing PHP version in subject )

I'm having some issues tonight. Today of course there was an announcement that CI version 3.1.3 was released. So, I ran my development builder for Community Auth, and can't log in. By default the builder sets me up with database sessions. Sometimes I am seeing this error message:

ERROR - 2017-01-09 19:55:20 --> Severity: Warning --> Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (ci_sessions) Unknown 0

I can switch to file based sessions and everything starts working fine, but broken again if I switch back to database sessions.

Also, if I set up my builder to pull in CI 3.1.2 instead of 3.1.3, everything works fine with the database sessions. So, I'm not quite sure what to do to debug. It could be a session issue, or maybe a database issue, I don't really know.

If it matters, here is my builder script:


Code:
#!/bin/bash
# This is the installer for those working on Community Auth development.
# Place and execute this script where IT WILL CREATE the web root directory.
# It will also create the database, as long as you set a valid user and password.

# The directory that git will clone into
SITEDIR="community_auth_ci_3"

# The base_url for CodeIgniter
# Note: make sure to escape slashes!
BASEURL="http:\/\/localhost.community_auth_ci_3\/"

# The name of the database to create
DBNAME="community_auth_ci_3"

# The DB user
DBUSER="root"

# The DB password
DBPASS=""

# If symlinks (soft links) should be used instead of copying files
SYMLINKS=false

# The CI download
CIDOWNLOAD="https://github.com/bcit-ci/CodeIgniter/archive/master.tar.gz"
# CIDOWNLOAD="https://github.com/bcit-ci/CodeIgniter/archive/3.1.2.tar.gz"

# -------------------------------------------------------------------------

# Make sure not already installed
if [ ! -d ./$SITEDIR ];
then
    # Clone the Community Auth repository on bitbucket
    git clone [email protected]:skunkbad/community-auth-for-codeigniter-3.git $SITEDIR

    # The web root directory should now exist
    if [ -d ./$SITEDIR ];
    then
        # Move into web root
        cd ./$SITEDIR

        # Temporarily move Community Auth
        mv ./application/third_party/community_auth/ ./community_auth_tmp/
        rm -r ./application

        # Temp file deleted after extract
        TMPFILE=`mktemp`

        # Download and extract CodeIgniter (skip old files so .gitignore is not replaced)
        wget $CIDOWNLOAD -O $TMPFILE
        tar -xf $TMPFILE --skip-old-files --strip 1
        rm $TMPFILE

        # Restore Community Auth to its third party location
        mv ./community_auth_tmp/ ./application/third_party/community_auth/

        # Move into application directory
        cd ./application

        # Copy or symlink core files
        if [ "$SYMLINKS" = true ];
        then
            ln -s ../third_party/community_auth/core/MY_Controller.php ./core/MY_Controller.php
            ln -s ../third_party/community_auth/core/MY_Input.php ./core/MY_Input.php
            ln -s ../third_party/community_auth/core/MY_Model.php ./core/MY_Model.php
        else
            cp ./third_party/community_auth/core/MY_Controller.php ./core/MY_Controller.php
            cp ./third_party/community_auth/core/MY_Input.php ./core/MY_Input.php
            cp ./third_party/community_auth/core/MY_Model.php ./core/MY_Model.php
        fi

        # Copy or symlink hook files
        if [ "$SYMLINKS" = true ];
        then
            ln -s ../third_party/community_auth/hooks/auth_constants.php ./hooks/auth_constants.php
            ln -s ../third_party/community_auth/hooks/auth_sess_check.php ./hooks/auth_sess_check.php
        else
            cp ./third_party/community_auth/hooks/auth_constants.php ./hooks/auth_constants.php
            cp ./third_party/community_auth/hooks/auth_sess_check.php ./hooks/auth_sess_check.php
        fi

        # Copy or symlink controller files
        if [ "$SYMLINKS" = true ];
        then
            ln -s ../third_party/community_auth/controllers/Examples.php ./controllers/Examples.php
            ln -s ../third_party/community_auth/controllers/Key_creator.php ./controllers/Key_creator.php
        else
            cp ./third_party/community_auth/controllers/Examples.php ./controllers/Examples.php
            cp ./third_party/community_auth/controllers/Key_creator.php ./controllers/Key_creator.php
        fi

        # Copy or modify main .htaccess
        cp ./third_party/community_auth/public_root/.htaccess ./../.htaccess

        # Add autoload configuration
        sed -i "s/\['packages'\] = array()/\['packages'\] = array(\n\tAPPPATH . 'third_party\/community_auth\/'\n)/g; \
s/\['libraries'\] = array()/\['libraries'\] = array(\n\t'database','session','tokens','Authentication'\n)/g; \
s/\['helper'\] = array()/\['helper'\] = array(\n\t'serialization','cookie'\n)/g; \
s/\['config'\] = array()/\['config'\] = array(\n\t'db_tables','authentication'\n)/g; \
s/\['model'\] = array()/\['model'\] = array(\n\t'auth_model'\n)/g;" ./config/autoload.php

        # Add route to login page
        echo "\$route[LOGIN_PAGE] = 'examples/login';" >> ./config/routes.php

        # Change home page to examples/home
        sed -i "s/\['default_controller'\] = 'welcome'/\['default_controller'\] = 'examples\/home'/g" ./config/routes.php

        # Set base_url, index_page, turn hooks on, add an encryption key, and configure sessions
        sed -i "s/\['base_url'\] = ''/\['base_url'\] = '$BASEURL'/g; \
s/\['index_page'\] = 'index.php'/\['index_page'\] = ''/g; \
s/\['enable_hooks'\] = FALSE/\['enable_hooks'\] = TRUE/g; \
s/\['encryption_key'\] = ''/\['encryption_key'\] = hex2bin('5d3a06b1a1efeb861ad761fb8839794f')/g; \
s/\['sess_driver'\] = 'files'/\['sess_driver'\] = 'database'/g; \
s/\['sess_cookie_name'\] = 'ci_session'/\['sess_cookie_name'\] = 'ciSess'/g; \
s/\['sess_save_path'\] = NULL/\['sess_save_path'\] = 'ci_sessions'/g; \
s/\['sess_regenerate_destroy'\] = FALSE/\['sess_regenerate_destroy'\] = TRUE/g;" ./config/config.php

        # Add hooks
        printf "\$hook['pre_system'] = array(\n\t'function' => 'auth_constants',\n\t'filename' => 'auth_constants.php',\n\t'filepath' => 'hooks'\n);\n\$hook['post_system'] = array(\n\t'function' => 'auth_sess_check',\n\t'filename' => 'auth_sess_check.php',\n\t'filepath' => 'hooks'\n);" >> ./config/hooks.php

        # Create DB
        if [ -n "$DBPASS" ];
        then
            mysqladmin -u $DBUSER -p$DBPASS create $DBNAME
            cat ./third_party/community_auth/sql/install.sql | mysql -u $DBUSER -p$DBPASS $DBNAME
        else
            mysqladmin -u $DBUSER create $DBNAME
            cat ./third_party/community_auth/sql/install.sql | mysql -u $DBUSER $DBNAME
        fi

        # Configure DB
        if [ -n "$DBPASS" ];
        then
            sed -i "s/'username' => ''/'username' => '$DBUSER'/g; \
s/'password' => ''/'password' => '$DBPASS'/g; \
s/'database' => ''/'database' => '$DBNAME'/g;" ./config/database.php
        else
            sed -i "s/'username' => ''/'username' => '$DBUSER'/g; \
s/'database' => ''/'database' => '$DBNAME'/g;" ./config/database.php
        fi

        # Pretty URLs
        printf "\n\nRewriteEngine On\nRewriteBase /\n\nRewriteRule ^(system|application|cgi-bin) - [F,L]\nRewriteCond %%{REQUEST_FILENAME} !-f\nRewriteCond %%{REQUEST_FILENAME} !-d\nRewriteRule .* index.php/\$0 [PT,L]" >> ./../.htaccess

        # Checkout develop from origin
        git checkout -b develop origin/develop

        # Success
        echo "REMOVE INSTALLER SCRIPT (THIS FILE)."
    else
        # Error
        echo "INSTALLER ERROR: COMMUNITY AUTH DIR DOES NOT EXIST."
    fi
else
    # Error
    echo "INSTALLER ERROR: COMMUNITY AUTH DIR ALREADY EXISTS."
fi

Session config is what I always use:

PHP Code:
$config['sess_driver'] = 'database';
$config['sess_cookie_name'] = 'ciSess';
$config['sess_expiration'] = 7200;
$config['sess_save_path'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_time_to_update'] = 300;
$config['sess_regenerate_destroy'] = TRUE

Same with DB config:

PHP Code:
$db['default'] = array(
    
'dsn'    => '',
    
'hostname' => 'localhost',
    
'username' => 'root',
    
'password' => '',
    
'database' => 'community_auth_ci_3',
    
'dbdriver' => 'mysqli',
    
'dbprefix' => '',
    
'pconnect' => FALSE,
    
'db_debug' => (ENVIRONMENT !== 'production'),
    
'cache_on' => FALSE,
    
'cachedir' => '',
    
'char_set' => 'utf8',
    
'dbcollat' => 'utf8_general_ci',
    
'swap_pre' => '',
    
'encrypt' => FALSE,
    
'compress' => FALSE,
    
'stricton' => FALSE,
    
'failover' => array(),
    
'save_queries' => TRUE
); 

With sess_match_ip set to FALSE, here is my table:

Code:
CREATE TABLE IF NOT EXISTS `ci_sessions` (
 `id` varchar(128) NOT NULL,
 `ip_address` varchar(45) NOT NULL,
 `timestamp` int(10) unsigned DEFAULT 0 NOT NULL,
 `data` blob NOT NULL,
 PRIMARY KEY (`id`),
 KEY `ci_sessions_timestamp` (`timestamp`)
) ENGINE = MyISAM DEFAULT CHARSET utf8 COLLATE utf8_general_ci;


Anything to know about 3.1.3? This is just a standard issue Ubuntu 14.04 box. PHP 5.5. MariaDB 10.1.20.
Reply
#2

(This post was last modified: 01-11-2017, 12:17 AM by skunkbad.)

It looks like the use of sess_regenerate with the sole parameter set to TRUE is the problem. Why this is only a problem for my PHP 5.5 box I don't know.
Reply
#3

Try with this: https://github.com/bcit-ci/CodeIgniter/c...fc4b1d4db9
Reply
#4

(01-11-2017, 03:06 AM)Narf Wrote: Try with this: https://github.com/bcit-ci/CodeIgniter/c...fc4b1d4db9

Works for me. Hopefully it works for everyone.

Side note: I read in the PHP docs for sess_regenerate_id that the practice of destroying old session data immediately should not be done.


Quote:You should not destroy old session data immediately, but should use destroy time-stamp and control access to old session ID. Otherwise, concurrent access to page may result in inconsistent state, or you may have lost session, or it may cause client(browser) side race condition and may create many session ID needlessly. Immediate session data deletion disables session hijack attack detection and prevention also.


I'm not sure if this points to what was going on with this PHP 5.5 box, but this idea of having a destroy time-stamp is interesting. Maybe a future CI 3.x enhancement?
Reply
#5

It's optional - if it causes problems (with AJAX requests), that's everything you need really.

And I wouldn't pay that much attention to that note, knowing who wrote it ... I'll only say that not every php-internals dev is a sane person.
Reply
#6

Thanks for your attention. What happens now? Does this get put into 3.1.4?
Reply
#7

Naturally, yes.
Reply
#8

Great. The src code fix worked for me.  I ran into same issue with 3.1.3 testing with basic Community Auth.
Reply
#9

(01-12-2017, 11:15 AM)fangstar Wrote: Great. The src code fix worked for me.  I ran into same issue with 3.1.3 testing with basic Community Auth.

Community Auth was just updated last night, and the update makes it so the session ID regeneration after login matches the config option for sess_regenerate_destroy. Because the default is FALSE, unless somebody is setting it to TRUE, they would not need to apply the fix shown above.

See: https://bitbucket.org/skunkbad/community...66b2feaf71
Reply




Theme © iAndrew 2016 - Forum software by © MyBB