PHP 4.0 Bug #6202 Updated: Global variables get corrupted while retrieving from a query result
| From: | Bug Database | Date: | Wed, 06 Sep 2000 19:07:33 +0000 |
| Subject: | PHP 4.0 Bug #6202 Updated: Global variables get corrupted while retrieving from a query result | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-32440@lists.php.net to get a copy of this message | ||
ID: 6202
User Update by: gsohl@freedomgroup.com
Status: Open
Bug Type: MSSQL related
Description: Global variables get corrupted while retrieving from a query result
Still happening in 4.0.2.
Previous Comments:
[2000-08-16 17:26:27] gsohl@freedomgroup.com
This was against a MS SQL 6.5 server. My PHP.INI contains
extension=php_mssql70.dll
---------------------------------------------------------------------------
[2000-08-16 16:30:36] gsohl@freedomgroup.com
I've discovered a sequence of code that causes some global variables to become corrupted while
retrieving results from a query done through the native MSSQL interface. It happened while porting
the "Phorum" code to MSSQL (something I've done before, but am now doing again to the
latest Phorum release). When this occurs, the script never stops executing, however the output does
get flushed to the browser.
There is one file required to be included with this source. It is the MSSQL access class for Phorum
that I've coded. I'll include it at the bottom of this message.
Please contact me if you need any assistance in testing or any additional info. Thanks.
Greg Sohl
gsohl@freedomgroup.com
Here is the code that causes the error condition (with several debug echos included):
<?PHP
require('mssql.php');
// initialize database variables
$dbName='Support';
$dbUser='sa';
$dbPass='xxxxxxxx';
$dbServer='TFG_WWW';
// create database classes
if ( defined( "_DB_LAYER" ) && $dbName!=''){
$DB = new db();
$DB->open($dbName, $dbServer, $dbUser, $dbPass);
$q = new query($DB); //dummy query for generic operations
}
$sSQL = "Select thread from testforum where thread > 0 order by thread desc";
$thread_list = new query($DB, $sSQL);
echo "max = $max, min = $min<BR>";
echo 'Pos 1<BR>';
$rec = array();
$rec['thread'] = 5;
$rec=$thread_list->getrow();
if(isset($rec['thread'])){
$max=$rec["thread"];
echo "Pos 2 - max = $max<BR>";
while (is_array($rec)){
echo "Pos 3 - min = $min<BR>";
echo "1 - max = $max, min = $min<BR>";
$min=$rec["thread"];
echo "2 - max = $max, min = $min<BR>";
$rec=$thread_list->getrow();
echo "3 - max = $max, min = $min<BR>";
}
echo "4 - max = $max, min = $min<BR>";
}
else{
$max=0;
$min=0;
}
echo "5 - max = $max, min = $min<BR>";
?>
Here is the output from the code:
max = , min =
Pos 1
Pos 2 - max = 5
Pos 3 - min =
1 - max = 5, min =
2 - max = 5, min = 5
3 - max = 5, min = 5
Pos 3 - min = 5
1 - max = 5, min = 5
2 - max = 0, min = 5
3 - max = 0, min = 5713248
4 - max = , min = 5713248
5 - max = , min = 5713248
Here is the required file, mssql.php
<?PHP
$debug = 1;
if ( !defined( "_DB_LAYER" ) )
{
define("_DB_LAYER", 1 );
class db
{
var $connect_id;
var $type;
function db($database_type="mssql")
{
$this->type=$database_type;
}
function open($database, $host, $user, $password)
{
$this->connect_id=mssql_connect($host, $user, $password);
if ($this->connect_id)
{
$result=mssql_select_db($database);
if (!$result)
{
mssql_close($this->connect_id);
$this->connect_id=$result;
}
}
return $this->connect_id;
}
function drop_sequence($sequence)
{
$esequence=$sequence."_seq";
$sSQL="DROP TABLE $esequence";
$query=new query($this, $sSQL);
return $query->error();
}
function reset_sequence($sequence, $newval)
{
$this->nextid($sequence);
$esequence=$sequence."_seq";
$sSQL="Replace into $esequence values ('', $newval)";
$query=new query($this, $sSQL);
return $query->error();
}
function nextid($sequence)
{
// Not needed for MS SQL as we use an Identity field
// Function returns the next available id for $sequence, if it's not
// already defined, the first id will start at 1.
// This function will create a table for each sequence called
// '{sequence_name}_seq' in the current database.
/*
$esequence=ereg_replace("'","''",$sequence)."_seq";
$query=new query($this, "Select * from $esequence limit 1");
$query->query($this, "REPLACE INTO $esequence values ('', nextval+1)");
if ($query->result)
{
$result=mssql_insert_id($query->result);
}
else
{
$query->query($this, "CREATE TABLE $esequence ( seq char(1) DEFAULT '' NOT
NULL, nextval bigint(20) unsigned DEFAULT '0' NOT NULL auto_increment, PRIMARY KEY (seq),
KEY (nextval) )");
$query->query($this, "REPLACE INTO $esequence values ('', nextval+1)");
$result=mssql_insert_id($query->result);
}
*/
return 1;
}
function close()
{
// Closes the database connection and frees any query results left.
if ($this->query_id && is_array($this->query_id))
{
while (list($key,$val)=each($this->query_id))
{
mssql_free_result($val);
}
}
$result=mssql_close($this->connect_id);
return $result;
}
};
/************************************** QUERY ***************************/
class query
{
var $result;
var $row;
var $error = 0;
function query(&$db, $query="")
{
global $debug;
// Constructor of the query object.
// executes the query, notifies the db object of the query result to clean
// up later
if ($query!="")
{
// if ($this->result) {
// $this->free(); // query not called as constructor therefore there may
// be something to clean up.
// }
if ($debug==1) echo "n<!--$query-->n";
$this->error=0;
$this->result=mssql_query($query, $db->connect_id);
if (!$this->result)
$this->error=1;
return $this->result;
}
}
function getrow()
{
// Gets the next row for processing with $this->field function later.
$this->row=mssql_fetch_array($this->result);
return $this->row;
}
function numrows()
{
// Gets the number of rows returned in the query
$result=mssql_num_rows($this->result);
return $result;
}
function error()
{
// Gets the last error message reported for this query
// $result="";
return $this->error;
}
function field($field, $row="-1")
{
// get the value of the field with name $field
// in the current row or in row $row if supplied
if ($row!=-1)
{
$result=mssql_result($this->result, $row, $field);
}
else{
$result=$this->row[$field];
}
if(isset($result))
{
return $result;
}
else
{
return '0';
}
}
function firstrow()
{
// return the current row pointer to the first row
// (CAUTION: other versions may execute the query again!! (e.g. for oracle))
$result=mssql_data_seek($this->result,0);
if ($result)
{
$result=$this->getrow();
}
return $this->row;
}
function free()
{
// free the mssql result tables
return mssql_free_result($this->result);
}
}; // End class
// Custom Create Table Section
function create_table(&$DB, $table, $table_name)
{
GLOBAL $q, $debug;
$errormsg = '';
if($table=="main")
{
$sSQL="CREATE TABLE $table_name (id int DEFAULT '0' NOT NULL, datestamp datetime
DEFAULT '0000-00-00 00:00:00' NOT NULL, thread int DEFAULT '0' NOT NULL, parent
int DEFAULT '0' NOT NULL, author char(37) DEFAULT '' NOT NULL, subject char(50)
DEFAULT '' NOT NULL, email char(50) DEFAULT '' NOT NULL, host char(50) DEFAULT
'' NOT NULL, email_reply char(1) NOT NULL DEFAULT 'N', approved char(1) NOT NULL
DEFAULT 'N', PRIMARY KEY (id))";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if(!$q->error())
{
$sSQL="CREATE INDEX author ON $table_name (author)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if(!$q->error())
{
$sSQL="CREATE INDEX datestamp ON $table_name (datestamp)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if(!$q->error())
{
$sSQL="CREATE INDEX subject ON $table_name (subject)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if(!$q->error())
{
$sSQL="CREATE INDEX thread ON $table_name (thread)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if(!$q->error())
{
$sSQL="CREATE INDEX parent ON $table_name (parent)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
}
else
$errormsg = $q->error();
}
else
$errormsg = $q->error();
}
else
$errormsg = $q->error();
}
else
$errormsg = $q->error();
$sSQL="CREATE TABLE ".$table_name."_bodies (id int IDENTITY NOT NULL, body text
DEFAULT '' NOT NULL, thread int DEFAULT '0' NOT NULL, PRIMARY KEY (id))";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if($q->error())
{
$errormsg = $q->error();
$sSQL="DROP TABLE ".$table_name;
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
return $errormsg;
}
else
{
$sSQL="CREATE INDEX thread ON ".$table_name."_bodies (thread)";
echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if($q->error())
{
$errormsg = $q->error();
$sSQL="DROP TABLE ".$table_name;
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
$sSQL="DROP TABLE ".$table_name."_bodies";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
return $errormsg;
}
return "";
}
}
else
$errormsg = $q->error();
}
elseif($table=="forums")
{
echo 'Creating the main Forums table';
$sSQL="CREATE TABLE ".$table_name." (
id int DEFAULT '0' NOT NULL,
name char(50) DEFAULT '' NOT NULL,
active smallint DEFAULT 0 NOT NULL,
description char(255) DEFAULT '' NOT NULL,
config_suffix char(50) DEFAULT '' NOT NULL,
folder char(1) DEFAULT '0' NOT NULL,
parent int DEFAULT 0 NOT NULL,
display int DEFAULT 0 NOT NULL,
table_name char(50) DEFAULT '' NOT NULL,
moderation char(1) DEFAULT 'n' NOT NULL,
mod_email char(50) DEFAULT '' NOT NULL,
mod_pass char(50) DEFAULT '' NOT NULL,
email_list char(50) DEFAULT '' NOT NULL,
email_return char(50) DEFAULT '' NOT NULL,
check_dup smallint DEFAULT 0 NOT NULL,
multi_level smallint DEFAULT 0 NOT NULL,
collapse smallint DEFAULT 0 NOT NULL,
flat smallint DEFAULT 0 NOT NULL,
staff_host char(50) DEFAULT '' NOT NULL,
lang char(50) DEFAULT '' NOT NULL,
html char(40) DEFAULT 'N' NOT NULL,
table_width char(4) DEFAULT '' NOT NULL,
table_header_color char(7) DEFAULT '' NOT NULL,
table_header_font_color char(7) DEFAULT '' NOT NULL,
table_body_color_1 char(7) DEFAULT '' NOT NULL,
table_body_color_2 char(7) DEFAULT '' NOT NULL,
table_body_font_color_1 char(7) DEFAULT '' NOT NULL,
table_body_font_color_2 char(7) DEFAULT '' NOT NULL,
nav_color char(7) DEFAULT '' NOT NULL,
nav_font_color char(7) DEFAULT '' NOT NULL,
PRIMARY KEY (id) )";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if (!$q->error())
{
$sSQL="CREATE INDEX name ON $table_name (name)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if (!$q->error())
{
$sSQL="CREATE INDEX active ON $table_name (active)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
if (!$q->error())
{
$sSQL="CREATE INDEX parent ON $table_name (parent)";
if ($debug==1) echo "n<!--$sSQL-->n";
$q->query($DB, $sSQL);
$errormsg = $q->error();
}
else
$errormsg = $q->error();
}
else
$errormsg = $q->error();
}
else
$errormsg = $q->error();
}
return $errormsg;
}
}
?>
Here is the SQL to create the table:
CREATE TABLE dbo.testforum (
id int NOT NULL ,
datestamp datetime NOT NULL ,
thread int NOT NULL ,
parent int NOT NULL ,
author char (37) NOT NULL ,
subject char (50) NOT NULL ,
email char (50) NOT NULL ,
host char (50) NOT NULL ,
email_reply char (1) NOT NULL ,
approved char (1) NOT NULL
)
And finally, here's a script to insert some data:
insert into testforum (id,datestamp,thread,parent,author,subject,email,host,email_reply,approved)
values(5,'Aug 16 2000 12:39PM',5,0,'Greg Sohl','Test
Posting','gsohl@freedomgroup.com','GSOHL1','','Y')
GO
insert into testforum (id,datestamp,thread,parent,author,subject,email,host,email_reply,approved)
values(6,'Aug 16 2000 12:41PM',5,5,'Greg Sohl','RE: Test
Posting','gsohl@freedomgroup.com','GSOHL1','','Y')
GO
---------------------------------------------------------------------------
The remainder of the comments for this report are over the 10k message limit. To view the remainder
of the comments, please review the bug report online.
Full Bug description available at: http://bugs.php.net/?id=6202