ID:               24463
 User updated by:  nospam at kolbly dot com
 Reported By:      nospam at kolbly dot com
 Status:           Open
-Bug Type:         Feature/Change Request
+Bug Type:         ODBC related
 Operating System: Win2003 Server
 PHP Version:      4.3.2
 New Comment:

Some progress is being made on Microsoft's end and we seem to have a
viable working workaround now that does NOT involve slowing down page
redirects.  This appears to work under both Win2000 and Win2003.  

When IIS spits out a 502 error, it appears that our CGI exe does not
even get loaded.  When IIS first loads up the CGI exe - it appears to
fail during a Loadlibrary() call.  Which library fails to load is still
undetermined because so far when any debuggers are attached to the IIS
process, the problem cannot be reproduced.  The best working theory at
this point is that some ODBC code is setting up a very fast global lock
that IIS can subsequently run into later on if the next call is fast
enough.  The workaround involves running the CGI as the "system"
account instead of a "user" account by changing a setting in the IIS
metabase.  The system account apparently does not have a problem with
our potential global locks not releasing.

To change the IIS metabase setting, create a VBS file called fixiis.vbs
and paste the following code there :
dim oIISObj 
Set oIISObj = GetObject("IIS://localhost/W3SVC/1/Root") 
oIISObj.CreateProcessAsUser = False 
oIISObj.SetInfo 
Set oIISObj = nothing

So far this has "Fixed" my problem on every configuration I've tried. 
If you want to do this, please do consider the security considerations
of running your PHP code under the system account


Previous Comments:
------------------------------------------------------------------------

[2003-07-08 15:19:59] [EMAIL PROTECTED]

As for the ODBC code, yes it is all based on ODBC v2, a large
percentage of which has been depricated.  There is movement to udpate
this, but ODBC spec REQUIRES that there be backwards compatiblity
options with newer spec drivers.  I don't believe that is the issue at
all.  Not sure if this should be marked as IIS or ODBC related...

------------------------------------------------------------------------

[2003-07-08 15:01:58] nospam at kolbly dot com

An update and some additional comments :

I have been able to suck out odbc calls from the php source php_odbc.c
and been able to recreate the problem using code I'll post to the end
of this message.

I've successfully opened up a case w/Microsoft and they're in the
process of recreating the problem in their labs.  I'll post their
results here.

One note : php_odbc.c has many calls that are deprecated by Microsoft. 
This may or may not be a contributing factor.  I've been able to
successfully eliminate the problem on my test platform by adding a
Sleep(1) at the end of each of the following functions in php_odbc.c -
SQLFreeStmt(), SQLDisconnect(), SQLFreeConnect(), and SQLFreeEnv().  

Unrelated side note to PHP developers: When PHP is compiled with Cygwin
utils instead of the win32build\bin utils, then php.ini ALWAYS has a
parsing problem at the last line.  An update to the windows install doc
would likely save many a developer some frustration.  


breakiis.c .....

#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdlib.h>

#include <time.h>
#include <stdio.h>

#define MYSQLSUCCESS(rc)
((rc==SQL_SUCCESS)||(rc==SQL_SUCCESS_WITH_INFO))
#define MAX_NAMES       100
#define MAX_NAME_SIZE 25

#define DSN     "bug"                                   // ODBC System Data Source, 
points to Northwind
DB
#define DB_USER "buguser"               // Database user with privileges on
Northwind DB
#define DB_PASS "bugpass"               // Database password

#define LOGFILE "d:\\weblogs\\mydebug.log"

void single_page_load();
void auto_reload_page();
void get_data_using_odbc(int *count, char names[][MAX_NAME_SIZE]);

void mydebug(const char *msg);

/**

****************************************************************************
 * main()
 *
 * Try to break IIS using native ODBC funcs

****************************************************************************
 */
int main(int argc, char* argv[])
{
        mydebug("main() start...");

        auto_reload_page();

        mydebug("main() end...");

        return 0;
}


/**

****************************************************************************
 * get_data_using_odbc()
 *
 * Connect to the SQL Server 2000 Database Northwind
 * Setup an ODBC DataSource named DSN, a Database user DB_USER, and 
 * password DB_PASS.

****************************************************************************
 */
void get_data_using_odbc(int *count, char names[][MAX_NAME_SIZE])
{
   RETCODE rc;                                          // ODBC return code
   HENV henv;                                           // Environment   
   HDBC hdbc;                                           // Connection handle
   HSTMT hstmt;                                 // Statement handle
   unsigned char szData[100];   // Returned data storage
   SDWORD cbData;                                       // Output length of data
        int index = 0;
        DWORD zzz = 1;                                  // Sleep period - Set to 1 to 
aleviate problem

        mydebug("get_data_using_odbc() start...");


        // Connect Up
   SQLAllocEnv(&henv);
   SQLAllocConnect(henv,&hdbc);

   rc = SQLConnect(hdbc, (SQLCHAR *)DSN, SQL_NTS, (SQLCHAR *)DB_USER,
SQL_NTS, (SQLCHAR *)DB_PASS, SQL_NTS);
   
        // Exec Stmt
   rc = SQLAllocStmt(hdbc,&hstmt);
  
        rc = SQLExecDirect(hstmt, (SQLCHAR *)"SELECT FirstName FROM
employees", SQL_NTS);

        for (rc = SQLFetch(hstmt); (rc == SQL_SUCCESS) && (index < MAX_NAMES);
rc=SQLFetch(hstmt))
   {
                SQLGetData(hstmt, 1, SQL_C_CHAR, szData, sizeof(szData), &cbData);
                sprintf(names[index], "%s", (const char *) szData);
                index++;
   }
        *count = index;

   SQLFreeStmt(hstmt, SQL_DROP);
                //Sleep(zzz);

   rc = SQLDisconnect(hdbc);
                //Sleep(zzz);

   rc = SQLFreeConnect(hdbc);
                //Sleep(zzz);

        rc = SQLFreeEnv(henv);
                //Sleep(zzz);

        mydebug("get_data_using_odbc() end...");

}// get_data_using_odbc()


/**

****************************************************************************
 * auto_reload_page()
 *
 * Have the web page keep reloading itself while incrementing a
counter

****************************************************************************
*/
void auto_reload_page()
{
        char *data;
        double count;

        int i;
        char names[MAX_NAMES][MAX_NAME_SIZE];
        int num = 0;

        mydebug("auto_reload_page() start...");

        ZeroMemory(names, sizeof(names));

        // Comment out below and this page reloads just fine
        get_data_using_odbc(&num, names);

        data = getenv("QUERY_STRING");
        if(data == NULL) 
                count=1;
        else
                count = atof(data);

        printf("content-type: text/html\n\n");

        printf("<html>");
        printf("<head>");
        printf("<title>BreakIIS</title>");
        printf("<meta http-equiv=\"Content-Type\" content=\"text/html;
charset=iso-8859-1\">");
        printf("</head>");
        printf("<body>");
        printf("Loading page with value %5f<br><br>\n", count);
        count++;

        for (i = 0; i < num; i++) {
                printf("%s<br>\n", names[i]);
        }

        printf("<script>location.href='breakiis.exe?%f'</script>", count);

        printf("</body>");
        printf("</html>");
        
        mydebug("auto_reload_page() end...");

}// auto_reload_page()


/**

****************************************************************************
 * void single_page_load()
 *
 * Have the web page keep reloading itself once the user presses
"submit"

****************************************************************************
*/
void single_page_load()
{
        int i;
        char names[MAX_NAMES][MAX_NAME_SIZE];
        int num = 0;

        ZeroMemory(names, sizeof(names));

        get_data_using_odbc(&num, names);

        printf("content-type: text/html\n\n");

        printf("<html>");
        printf("<head>");
        printf("<title>BreakIIS</title>");
        printf("<meta http-equiv=\"Content-Type\" content=\"text/html;
charset=iso-8859-1\">");
        printf("</head>");
        printf("<body>");

        for (i = 0; i < num; i++) {
                printf("%s<br>\n", names[i]);
        }

        printf("<form name=\"form1\" method=\"post\"
action=\"breakiis.exe\">");
        printf("<p>Click Submit to post back to this page.</p>");
        printf("<input type=\"submit\" name=\"Submit\" value=\"Submit\">");
        printf("</form>");

        printf("</body>");
        printf("</html>");

}// single_page_load()

/**

****************************************************************************
 * mydebug()
 *
 * Simply write a logfile to LOGFILE

****************************************************************************
 */
void mydebug(const char *msg)
{

        char datetime[120];
        FILE *f;
        time_t curtime;
        struct tm *loctime;

        ZeroMemory(datetime, sizeof(datetime));

        curtime = time(NULL);
        loctime = localtime(&curtime);
        strftime(datetime, 119, "%Y-%m-%d %H:%M:%S", loctime);

        f = fopen(LOGFILE, "a");
        if (f) {
                fprintf(f, "%s : %s\n", datetime, msg);
                fclose(f);
        }

}// mydebug()

------------------------------------------------------------------------

[2003-07-02 13:19:35] nospam at kolbly dot com

Description:
------------
When redirecting to a .php page that connects to an SQL Server database
via ODBC, IIS produces a 502 error intermittently on slower machines
and 100% on faster machines.

This is admittedly a duplicate of Bug #9852 (Which is currently
closed),  but my tests have pointed that the problem is with PHP, not
IIS.  

I have opened up an Incident with Microsoft and we are at the point
where if I can reproduce the bug using some non-php code, they will
duplicate my setup exactly in their lab and have their developers
tackle it.  But, so far I cannot reproduce the error with any non-php
code.  I traced the php function calls, and wrote a C program that
calls the exact same odbc calls as php, but this does NOT break IIS.  I
can only conclude that the issue is within PHP or Zend or at the very
least it is still very much in doubt as to which code is at fault
here.

I have tried ALL the suggested workarounds from Bug #9852 with no luck.
 I will be forced to rewrite 8 websites in .asp or .net if I can’t fix
this.   

If anybody has a way to reproduce this error using C/C++/C#/ASP or some
other “Microsoft-Approved” language, please send me your source code.
([EMAIL PROTECTED])


Reproduce code:
---------------
<?php
$dbconn = odbc_connect("bug", "buguser", "bugpass");
$rs = odbc_exec($dbconn, "select * from employees");
while(odbc_fetch_row($rs)) {
        $EmployeeID = odbc_result($rs, "EmployeeID");
}
if (isset($_POST['Submit'])) {
        header("Location: test1a.php"); die;
}
?>
<html>
<head>
<title>Bug Test</title>
<meta http-equiv="Content-Type" content="text/plain;
charset=iso-8859-1">
</head>
<body>
<form name="form1" method="post" action="test1a.php">
<p>Click Submit to post back to this page.</p>
<input type="submit" name="Submit" value="Submit">
</form>
</body>
</html>

Expected result:
----------------
Click Submit to post back to this page.

[Submit]

Actual result:
--------------
CGI Error
The specified CGI application misbehaved by not returning a complete
set of HTTP headers.


------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=24463&edit=1

Reply via email to