Link to home
Start Free TrialLog in
Avatar of DerryLyons
DerryLyons

asked on

$_SESSION variable value with single quotes

I have a series of PHP scripts that authenticate a user (or, if not authenticated, redirect), and set a series of $_SESSION variables based on values stored in our employee database. All logins are standard characters, and the scripts are working fine, until I go to set $_SESSION['lname'] to odbc_result from the database that contains O'Brien. I've tried using addslashes() and htmlspecialchars()... but it doesn't seem to actually get set. Since I'm not prep'ing a statement for insert to the database, it's more having this string variable for reference later on, what would be the correct way to retrieve and maintain the apostrophe?

BTW, doing nothing just crashes the script with a generic 500 error in the browser. At least addslashes() will get the script to run, but variables aren't brought forth.

(Code snippets can be provided on request...  running on Windows/Apache)  Thanks! :) Derry
Avatar of biztiger
biztiger
Flag of India image

It is strange that your problem didn't solve with addslashes(). Please provide the code snippet so I can help.
Alternatively you can check
addcslashes($your_odbc_result_string,"'");
Why don't you store the name in variable and use $_SESSION['$name'] ?
Avatar of DerryLyons
DerryLyons

ASKER

I should mention that if I don't use addslashes() at all, it appears that the main script goes through a series of redirects to the auth/index.php then back again about 5 times and dies. Putting in addslashes() gets rid of the 500 error, but the variables still don't stick.

Below is a code snippet of the function where the variables are set. (I've also temporarily added some logging code that writes the variables to a file, so they ARE getting set...)

Below that is how I'm referencing them in the main script.

addcslashes() didn't seem to work any differently.

Thanks! :) Derry
function populate_session_info($login,$SID) {
  
  require_once('DBlib.php');
 
  /* Lookup and populate name, location, etc. */
 
  if ($login) {
   $dbid = db_open('public');
   $sql = <<<ENDOFSQL
	SELECT STAFF.STAFF_NAME_ID, STAFF.STAFF_NAME_KEY, STAFF.STAFF_LAST, STAFF.STAFF_FIRST, DEPTS.DEPT_CODE,
	  DEPTS.DEPT_ENTITY, DEPTS.DEPT_NAME
    		FROM STAFF INNER JOIN
                         STAFF_ACCTS ON STAFF.STAFF_NAME_ID = STAFF_ACCTS.STAFF_NAME_ID INNER JOIN
                         STAFF_LOCS ON STAFF.STAFF_NAME_ID = STAFF_LOCS.STAFF_NAME_ID INNER JOIN
                          DEPTS ON STAFF_LOCS.STAFF_LOC_ID = DEPTS.STAFF_LOC
    	WHERE     (STAFF_ACCTS.STAFF_ACCT_TYPE = 'AD') AND (STAFF_ACCTS.STAFF_ACCT = '$login')
		AND (STAFF_LOCS.STAFF_LOC_PRIMARY = 1)
ENDOFSQL;
 
    $staffset=odbc_exec($dbid,$sql);
    if (!$staffset)
      {exit("Error in SQL retrieving name info");}
 
    odbc_fetch_row($staffset);
 
    $_SESSION['user'] = $login;
    $_SESSION['nameid'] = odbc_result($staffset,"STAFF_NAME_ID");
 
    $_SESSION['fname'] = odbc_result($staffset,"STAFF_FIRST");
    $_SESSION['locid'] = odbc_result($staffset,"DEPT_CODE");
    $_SESSION['locname'] = odbc_result($staffset,"DEPT_NAME");
    $_SESSION['entity'] = odbc_result($staffset,"DEPT_ENTITY");
 
    //$_SESSION['lname'] = odbc_result($staffset,'STAFF_LAST');
    //$_SESSION['namekey'] = odbc_result($staffset,'STAFF_NAME_KEY');
    $_SESSION['lname'] = addslashes(odbc_result($staffset,"STAFF_LAST"));
    $_SESSION['namekey'] = addslashes(odbc_result($staffset,"STAFF_NAME_KEY"));
 
    db_close($dbid);
 
    /* New logging routine */
 
$myFile = "sessionlog.txt";
$fh = fopen($myFile, 'a') or die("can't open file");
$logstr = '**SessID: ' . $sessid . ' -- SessionUser: ' . $_SESSION['user'] . ' -- SessionNameKey: ' . $_SESSION['namekey'] . ' -- SessionLastName: ' . $_SESSION['lname'];
fwrite($fh, $logstr . "\r\n");
//fwrite($fh, print_r($_SESSION));
fclose($fh); 
}
 
In php script to use variables...
 
  $lname = htmlspecialchars(stripslashes($_SESSION['lname']));
  echo "<B>". $_SESSION['fname']." ". $lname ."</B><BR>";
  echo "Location: " . $_SESSION['locid'] ."<BR>";

Open in new window

Try adding this to the script that loads the data into $_SESSION.  If you post the output, maybe we can help.

var_dump($_SESSION);

If you put that inside echo "<pre>" it will be easier to read!

HTH, ~Ray
Also, are all the scripts using session_start() at the top?
session_start() is being called at the beginning, just in a different subroutine. (Remember it's working great except for people with apostrophes in their last name or namekey... grrrrr!)

Here's the variable dump. Note that both lname and namekey have apostrophes...and somehow the ; is creeping into the ;namekey...

Array
(
    [user] => lyons
    [nameid] => 54321
    [fname] => Derry
    [locid] => TECH
    [locname] => Information Technology Services
    [entity] =>
    [lname] =>
    [;namekey] =>
    [edrmid] => 1234
    [barg_unit] => NRSUP
)

It can happen if your magic quotes are off. Refer to
http://in2.php.net/stripslashes

So, I think just modify in php script where you have to use variables like the following...

function stripslashes_if_gpc_magic_quotes( $string ) {
    if(get_magic_quotes_gpc()) {
        return stripslashes($string);
    } else {
        return $string;
    }
}
 
  $lname = htmlspecialchars(stripslashes_if_gpc_magic_quotes($_SESSION['lname']));
  echo "<B>". $_SESSION['fname']." ". $lname ."</B><BR>";
  echo "Location: " . $_SESSION['locid'] ."<BR>";

Open in new window

biztiger,
  Thanks for the code! I tried it, but the issue doesn't *appear* to be magic_quotes related.

  One of the symptoms is if I set $_SESSION['namekey'] = odbc_result($staffset,"STAFF_NAME_KEY"); (and it has an apostrophe), and even if I never use it in my other PHP code, I get the 500 error and none of the web pages are usable. (Leads me to believe it's an issue with the variable getting assigned...)

  If I change it to $_SESSION['namekey'] = addslashes(odbc_result($staffset,"STAFF_NAME_KEY")); then it doesn't error out, which is great, BUT the variable isn't being set either. :(
Another clue: If the variable assignment doesn't have addslashes() but the new value DOES have a single quote, the page returns a 500 error, and the following entries appear in the access.log file... with each redirect adding the SID on the end again.


168.212.206.15 - - [12/Nov/2008:15:37:23 -0800] "GET /apps/time/index.php HTTP/1.1" 302 -
168.212.206.15 - - [12/Nov/2008:15:37:29 -0800] "GET /apps/time/index.php??SID=f5ocn1pb394j4g65jhs4ukd5s6 HTTP/1.1" 302 -
168.212.206.15 - - [12/Nov/2008:15:37:29 -0800] "GET /apps/time/index.php??SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6 HTTP/1.1" 302 -
168.212.206.15 - - [12/Nov/2008:15:37:29 -0800] "GET /apps/time/index.php??SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6 HTTP/1.1" 302 -
168.212.206.15 - - [12/Nov/2008:15:37:29 -0800] "GET /apps/time/index.php??SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6 HTTP/1.1" 302 -
168.212.206.15 - - [12/Nov/2008:15:37:30 -0800] "GET /apps/time/index.php??SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6?SID=f5ocn1pb394j4g65jhs4ukd5s6 HTTP/1.1" 302 -

Open in new window

@DerryLyons: Would you please run this script and see if the cheese counter increments correctly?  It would help us rule out one possible issue with the session handler.  Thanks, ~Ray
<?php
session_start();
if (isset($_POST[submit])) {
	if(!isset($_SESSION['cheese'])) {
		$_SESSION['cheese'] = 1;
	} else {
		$_SESSION['cheese']++;
	}
}
?>
<html><head><title>Session Test</title></head>
<body>
Current Session Variable value is: <?= $_SESSION['cheese'] ?> <br/>
<form method="post">
<input type=submit value=click name=submit>
</form>
</body>
</html>

Open in new window

Cheese counter works great! Thanks for the continued efforts... :)
Great.  Now post a link to this script here, and I'll ruminate a little more about that strange semi-colon.
<?php phpinfo(); ?>

Open in new window

http://moodle.skitsap.wednet.edu/phpenv.php

I'm also planning on setting up a test environment next week to start isolating the code from the larger application, which may help us refine the problem statement.
Moodle, eh?!  Would have been great to have know that from the top!  Have you asked anything about this in the forums at Moodle.org or Moodle.com?

Also, can you post the data fields that come back from the query - before they are put into the Session variable?  I'm wondering if there is not something goofy in the data base.

Nothing looks wrong in phpinfo, so that's good news.

Hmm... ~Ray
Moodle is just the name of the box... the processes in question are not part of Moodle. So much for an easy fix. :)

I'm able to see the variables before they are set in $_SESSION (my first comment above... can write them out to a file)...
OK.  Is there any data construct that can get at all of the odbc_result($staffset) at once?  Like an object or an associative array?  I would love to see a var_dump() of that whole thing...
Sorry for the delay... the more we discussed it, the more suspicious I became and wanted to build perform some more tests. I think the apostrophes are a red herring with the true issue being the session variables not getting properly set. I've whittled down all of the libraries and function calls into the two scripts below, and no session variables get returned for ANYTHING, regardless of apostrophes.

The index.php file indicates the sessionid is set correctly, but the $_SESSION variables aren't coming across. (They *are* defined OK within the /auth/test script.)

I've gone back and reviewed the session documentation on php.net, but I'm thinking I'm missing something...


/apps/test/index.php -- "Main Menu"
 
<?php
 
  session_start();
  $sessionid = session_id();
  $sid = $_GET['SID'];
 
  if ($sid === NULL) {
//  if ($_SESSION['user'] === NULL) {
    $URL = $_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
    header("Location: https://moodle.skitsap.wednet.edu/apps/auth/test.php?URL=" . $URL);
    exit;
  }
 
echo "<pre>";
echo "Session ID: $sessionid<BR>";
print_r($_SESSION);
echo "</pre>";
 
?>
 
/auth/test.php -- under a password protected directory
 
<?php
 
/* Set the session variables */
ob_start();
session_start();
$sessid = session_id();
 
$login=$_SERVER['REMOTE_USER'];
 
$_SESSION['user'] = $login;
 
    /* New logging routine */
 
$myFile = "templog.txt";
$fh = fopen($myFile, 'a') or die("can't open file");
$logstr = '**SessID: ' . $SID . ' -- SessionUser: ' . $_SESSION['user'] . ' -- SessionNameKey: ' . $_SESSION['namekey'] . ' -- SessionLastName: ' . $_SESSION['lname'];
fwrite($fh, $logstr . "\r\n");
//fwrite($fh, print_r($_SESSION));
fclose($fh); 
 
 
session_write_close();
ob_end_flush();
 
 
/* Process and redirect */
foreach($_GET as $URL => $path) {
  $path = str_replace('_', '.', $path);
}
 
/* cleanup */
  $path = str_replace('?', '', $path);
 
 
/* Some code to define caching requirements...not sure this really matters...*/
header("Cache-Control: public, no-cache, must-revalidate, post-check=0, pre-check=0"); // HTTP/1.1
header("Pragma: no-cache");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
 
$redir = 'Location: http://moodle.skitsap.wednet.edu' . $path . '?SID=' . $sessid;
 
$myFile = "testauthlog.txt";
$fh = fopen($myFile, 'a') or die("can't open file");
$logstr = 'TIME: ' . time() . ' -- USER: ' . $_SESSION['user'] . ' -- PATH: ' . $path . ' -- SessID: ' . $sessid . ' -- RedirURL: ' . $redir;
fwrite($fh, $logstr . "\r\n");
fclose($fh); 
 
 
/* Redirect to the URL that was passed in */
 
if ($_SESSION['user'] === NULL) {
  echo "ERROR WITH SESSION";
} else {
  header($redir);
}
exit;
?>

Open in new window

Curious about something - why are you interested in session_id()?  I may be missing something, but I'm not following the logic in the post above.  What's it supposed to do/cause/prevent, etc.?
Since I was missing the $_SESSION variables, I was just checking to make sure session_id was coming through (and the same). The scripts I posted exhibit the problem... first script calls second script which sets $_SESSION then back to first script, but $_SESSION doesn't make it. I'm trying to get things more concise and defined...thanks for staying with me.

In looking at some other posts, it seems like save_path was critical, but I've rewritten the session handlers to insert to a mysql database... again, the odd part is it's mostly working in the production code, so it is getting set under normal circumstances...

:) Derry
SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well, that's a new one for me!  I would have thought that a session handler that used a data base would be using mysql_real_escape_string(), for sure.  Where did the session handler come from?
I'm not sure where I picked it up from (somewhere on the web), but I think you're right... a simple mysql_real_escape_string would probably do the trick... but the one thing you've stressed is simplicity, and since I don't *REALLY* need it, I'll go back to using files. Code is as follows FYI...


<?php
 
  /* DO NOT MODIFY THIS CODE! */
  /* These functions set the PHP behaviors for storing and retrieving cookies --
       it does NOT have anything to do with the actual applications or setting
       session variables     */
 
   mysql_connect("localhost", "dbname", "dbpassword");
   mysql_select_db("sessiondb");
 
   function sess_open($sess_path, $sess_name) {
      return true;
   }
 
   function sess_close() {
      return true;
   }
 
   function sess_read($sess_id) {
      $result = mysql_query("SELECT Data FROM sessions WHERE SessionID = '$sess_id';");
      if (!(mysql_num_rows($result))) {
         $CurrentTime = time();
         mysql_query("INSERT INTO sessions (SessionID, DateTouched) VALUES ('$sess_id', $CurrentTime);");
         return '';
      } else {
         $CurrentTime = time();
         extract(mysql_fetch_array($result), EXTR_PREFIX_ALL, 'sess');
         mysql_query("UPDATE sessions SET DateTouched = $CurrentTime WHERE SessionID = '$sess_id';");
         return $sess_Data;
      }
   }
 
   function sess_write($sess_id, $data) {
      $CurrentTime = time();
      mysql_query("UPDATE sessions SET Data = '$data', DateTouched = $CurrentTime WHERE SessionID = '$sess_id';");
      return true;
   }
 
   function sess_destroy($sess_id) {
      mysql_query("DELETE FROM sessions WHERE SessionID = '$sess_id';");
      return true;
   }
 
   function sess_gc($sess_maxlifetime) {
      $CurrentTime = time();
      mysql_query("DELETE FROM sessions WHERE DateTouched + $sess_maxlifetime < $CurrentTime;");
      return true;
   }
 
   session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");
 
 
?>

Open in new window

Yep, this is fatal.  Not only because it did not escape the information, but what would be the effect of having an object or an array in the session?  Gaack!

Some light reading here ;-)
http://us2.php.net/manual/en/intro.session.php

Anyway, glad you got it working.  Best regards, ~Ray
   function sess_write($sess_id, $data) {
      $CurrentTime = time();
      mysql_query("UPDATE sessions SET Data = '$data', DateTouched = $CurrentTime WHERE SessionID = '$sess_id';");
      return true;
   }

Open in new window