Jump to content

PHP Warning: Illegal string offset


Krillin

Recommended Posts

First off, I am NOT a programmer, but I have no problem diving into anything when it comes to web code. But for a few weeks I have been tracking down a few unknown issues and I do not know where to get help except here. I took over this project after not hearing back from the author since 2008. Normally I can fix issues, but this leap from PHP 5 to PHP 7/8 has got my head spinning. You would think after 10 years I would have a grasp on this by now, but I am not very efficient in PHP yet, but I will get there.

While running vsp.php in PHP 7.3.27 I am getting two warnings, but this one is rather urgent and may help me solve my second issue. So let's get to it!

I have researched the "PHP Illegal String Offset" and thought the offset was caused by an array set as an string. But the string is not set in the array for the savestate option passed from the CLI. I have not started tracking down the 'trackID' issue yet. Savestate is really important function as it prevents log files from being run for player stats a second time. Saving the savestate in a database is a very dumb idea for those who have log files for every map change like in HL1 - CS or CZ or HL2 CS:S and CSGO game mods like we do. I am stuck and cannot find or figure out a solution for these issues as I cannot figure out what the code is trying to do.

Issue #1: savestate value is passed from the CLI to turn on with a value of 1

Quote

PHP Warning:  Illegal string offset 'savestate' in vsp.php on line 979

This is what is on line 979.

$V0f14082c['parser-options'][$V51d3ee44['argv'][$V363b122c]]=$V51d3ee44['argv'][$V363b122c+1];

For clarification, here is the entire function within vsp.php.

 function F92261ca6()
{
    global $V51d3ee44;
    if (cIS_SHELL) {
        if (!isset($_SERVER['argc'])) {
            echo "Error: args not registered.\n";
            echo " register_argc_argv may need to be set to On in shell mode\n";
            echo " Please edit your php.ini and set variable register_argc_argv to On\n";
            F56fd05e9();
        }
        $V51d3ee44['argv']=$_SERVER['argv'];
        $V51d3ee44['argc']=$_SERVER['argc'];
    } else {
        $V4f96c5a0=$_POST['V70e78261'];
        if (get_magic_quotes_gpc()) {
            $V4f96c5a0=stripslashes($V4f96c5a0);
        }
        $V51d3ee44=F126ba7b1("vsp.php ".$V4f96c5a0);
    }
    global $V0f14082c;
    $V0f14082c['parser-options']="";
    $V0f14082c['prompt']=1;
    if ($V51d3ee44['argc']>1) {
        for ($V865c0c0b=1;$V865c0c0b<$V51d3ee44['argc']-1;$V865c0c0b++) {
            if (strcmp($V51d3ee44['argv'][$V865c0c0b], "-a")==0) {
                $V865c0c0b++;
                $V0f14082c['action']=$V51d3ee44['argv'][$V865c0c0b];
                if ($V0f14082c['action']!='clear_db') {
                    Facf3bf61("error: invalid action");
                }
                break;
            }
            if (strcmp($V51d3ee44['argv'][$V865c0c0b], "-n")==0) {
                $V0f14082c['prompt']=0;
                continue;
            }
            if ($V865c0c0b+1 > $V51d3ee44['argc']-2) {
                Facf3bf61("error: no value specified for option ".$V51d3ee44['argv'][$V865c0c0b]);
            }
            if (strcmp($V51d3ee44['argv'][$V865c0c0b], "-p")==0) {
                $V865c0c0b++;
                for ($V363b122c=$V865c0c0b;$V363b122c<$V51d3ee44['argc']-1;$V363b122c=$V363b122c+2) {
                    $V0f14082c['parser-options'][$V51d3ee44['argv'][$V363b122c]]=$V51d3ee44['argv'][$V363b122c+1]; //This is line 979
                }
                break;
            } elseif (strcmp($V51d3ee44['argv'][$V865c0c0b], "-c")==0) {
                $V865c0c0b++;
                $V0f14082c['config']=$V51d3ee44['argv'][$V865c0c0b];
            } elseif (strcmp($V51d3ee44['argv'][$V865c0c0b], "-l")==0) {
                $V865c0c0b++;
                $V0f14082c['log-gamecode']=$V51d3ee44['argv'][$V865c0c0b];
                $V0f14082c['log-gametype']='';
                if (preg_match("/(.*)-(.*)/", $V0f14082c['log-gamecode'], $Vb74df323)) {
                    $V0f14082c['log-gamecode']=$Vb74df323[1];
                    $V0f14082c['log-gametype']=$Vb74df323[2];
                    $V0f14082c['parser-options']['gametype']=$V0f14082c['log-gametype'];
                }
            } else {
                Facf3bf61("error: invalid option ".$V51d3ee44['argv'][$V865c0c0b]);
            }
        }
    } else {
        Facf3bf61("error: logfile not specified");
    }
    $V0f14082c['logfile']=$V51d3ee44['argv'][$V51d3ee44['argc']-1];
    if (!isset($V0f14082c['action'])) {
        if (!isset($V0f14082c['logfile'])) {
            Facf3bf61("error: logFile not specified");
        }
        if (!isset($V0f14082c['log-gamecode'])) {
            Facf3bf61("error: logType not specified");
        }
    }
    $V55d5b418="pub/configs/";
    if (!isset($V0f14082c['config']) || preg_match("/\\.\\./", $V0f14082c['config']) || !is_file($V55d5b418.$V0f14082c['config'])) {
        $V0f14082c['config']=$V55d5b418."cfg-default.php";
    } else {
        $V0f14082c['config']=$V55d5b418.$V0f14082c['config'];
    }
    echo "max_execution_time is ".ini_get("max_execution_time")."\n\n";
    echo "[command-line options]: ";
    print_r($V0f14082c);
    if (isset($V0f14082c['parser-options']['savestate']) && $V0f14082c['parser-options']['savestate']) {
        $Vb3521e13="writetest_".md5(uniqid(rand(), true));
        $V2880b5ba = fopen('./logdata/'.$Vb3521e13, "wb");
        if (!$V2880b5ba || !fwrite($V2880b5ba, "* WRITE TEST *\n")) {
            echo "Error: savestate 1 processing requires logdata/ directory to be writable.\n";
            echo " Enable write permissions for logdata/ directory (chmod 777)\n";
            F56fd05e9();
        }
        fclose($V2880b5ba);
        unlink("logdata/$Vb3521e13");
    }
}

And if needed. Here is the var_dump-s done to show what is stored in the variables used above in the line with the probem.

var_dump($V0f14082c);
array(6) {
  'parser-options' =>
  string(1) "g"
  'prompt' =>
  int(1)
  'log-gamecode' =>
  string(2) "hl"
  'log-gametype' =>
  string(0) ""
  'logfile' =>
  string(6) "./logs"
  'config' =>
  string(27) "pub/configs/cfg-default.php"
}

var_dump($V51d3ee44);
array(2) {
  'argv' =>
  array(7) {
    [0] =>
    string(7) "vsp.php"
    [1] =>
    string(2) "-l"
    [2] =>
    string(2) "hl"
    [3] =>
    string(2) "-p"
    [4] =>
    string(9) "savestate"
    [5] =>
    string(1) "1"
    [6] =>
    string(6) "./logs"
  }
  'argc' =>
  int(7)
}

var_dump($V865c0c0b)
NULL

var_dump($V363b122c)
NULL

Issue #2 tackID is set from a configuration file using the array from $cfg variable which can be one of many options, mainly for this case is GUID.

Quote

PHP Warning:  Illegal string offset 'trackID' in vsp.php on line 1038

This is the code on line 1038

$V0f14082c['parser-options']['trackID']=$GLOBALS['cfg']['parser']['trackID'];

For clarification, here is the entire function within vsp.php.

 function F68c076b3()
{
    global $V0f14082c;
    global $V51d3ee44;
    require_once($V0f14082c['config']);
    if (preg_match("/^ftp:\\/\\//i", $V0f14082c['logfile'])) {
        $V0f14082c['logfile']=Fd2c39001($V0f14082c['logfile']);
    }
    $V0f14082c['parser-options']['trackID']=$GLOBALS['cfg']['parser']['trackID']; // This is line 1038
    if (isset($GLOBALS['cfg']['db']['adodb_path'])) {
        $GLOBALS['cfg']['db']['adodb_path']=F9578dd1f($GLOBALS['cfg']['db']['adodb_path']);
    } else {
        $GLOBALS['cfg']['db']['adodb_path']=F9578dd1f(Ce5c65ec5).'pub/lib/adodb/';
    }
    require_once("{$GLOBALS['cfg']['db']['adodb_path']}".'adodb.inc.php');
    include_once("{$GLOBALS['cfg']['db']['adodb_path']}".'tohtml.inc.php');
    require_once("sql/{$GLOBALS['cfg']['db']['adodb_driver']}.inc.php");
    include_once("pub/include/playerBanList-{$GLOBALS['cfg']['player_ban_list']}.inc.php");
    foreach ($GLOBALS['player_ban_list'] as $V7fa3b767 => $V36190f8a) {
        $GLOBALS['player_ban_list'][$V7fa3b767]="/^".preg_quote($V36190f8a)."$/";
    }
    $GLOBALS['V9c1ebee8'] = &ADONewConnection($GLOBALS['cfg']['db']['adodb_driver']);
    global $V9c1ebee8;
    if (!$V9c1ebee8->Connect($GLOBALS['cfg']['db']['hostname'], $GLOBALS['cfg']['db']['username'], $GLOBALS['cfg']['db']['password'], $GLOBALS['cfg']['db']['dbname'])) {
        echo "Attempting to create/connect to database {$GLOBALS['cfg']['db']['dbname']}\n";
        $GLOBALS['V9c1ebee8'] = null;
        $GLOBALS['V9c1ebee8'] = &ADONewConnection($GLOBALS['cfg']['db']['adodb_driver']);
        global $V9c1ebee8;
        $V9c1ebee8->Connect($GLOBALS['cfg']['db']['hostname'], $GLOBALS['cfg']['db']['username'], $GLOBALS['cfg']['db']['password']);
        $V9c1ebee8->Execute($sql_create[0]);
        if (!$V9c1ebee8->Connect($GLOBALS['cfg']['db']['hostname'], $GLOBALS['cfg']['db']['username'], $GLOBALS['cfg']['db']['password'], $GLOBALS['cfg']['db']['dbname'])) {
            echo " - failed to create/connect to database {$GLOBALS['cfg']['db']['dbname']}\n";
            F56fd05e9();
        }
        echo " - database created\n";
    }
    if (isset($V0f14082c['action']) && $V0f14082c['action']=="clear_db") {
        if (cIS_SHELL && $V0f14082c['prompt']) {
            echo "Are you sure you want to clear the database {$GLOBALS['cfg']['db']['dbname']} @ {$GLOBALS['cfg']['db']['hostname']}? (y/n)\n";
            Fa10803e1();
            $Vd0cf705f=Fd63c38c9();
        } else {
            $Vd0cf705f='y';
        }
        if ($Vd0cf705f=='y' || $Vd0cf705f=='Y') {
            foreach ($sql_destroy as $V7fa3b767 => $Vac5c74b6) {
                $V9c1ebee8->Execute($Vac5c74b6);
            }
            print "{$GLOBALS['cfg']['db']['table_prefix']}* tables in {$GLOBALS['cfg']['db']['dbname']} @ {$GLOBALS['cfg']['db']['hostname']} has been cleared\n";
        }
        Fa3e3aec1();
    }
    foreach ($sql_create as $V7fa3b767 => $Vac5c74b6) {
        if ($V7fa3b767==0) {
            continue;
        }
        $V9c1ebee8->Execute($Vac5c74b6);
    }
    $V9c1ebee8->SetFetchMode(ADODB_FETCH_NUM);
    if (!is_dir("pub/games/{$GLOBALS['cfg']['game']['name']}")) {
        echo "Error: The variable \$cfg['game']['name'] is not set properly in config file.\n";
        echo " Edit your config file ({$V0f14082c['config']})\n";
        echo " Read the comments beside that variable and set that variable properly.\n";
        F56fd05e9();
    }
    if (!file_exists("vsp-{$V0f14082c['log-gamecode']}.php")) {
        Facf3bf61("error: unrecognized logType");
    }
    require_once("vsp-{$V0f14082c['log-gamecode']}.php");
    include_once("pub/games/{$GLOBALS['cfg']['game']['name']}/skillsets/{$GLOBALS['cfg']['skillset']}/{$GLOBALS['cfg']['skillset']}-skill.php");
    if (!isset($GLOBALS['skillset'])) {
        echo "Skill Definitions not found.\n";
        echo " "."pub/games/{$GLOBALS['cfg']['game']['name']}/skillsets/{$GLOBALS['cfg']['skillset']}/{$GLOBALS['cfg']['skillset']}-skill.php"."\n";
    }
    $V21d8a920 = new F622a322a();
    $Vae2aeb93 = new F02ac4643();
    $V8db265ff=strtoupper($V0f14082c['log-gamecode']);
    eval("\$V3643b863 = new VSPParser$V8db265ff(\$V0f14082c['parser-options'],\$V21d8a920,\$Vae2aeb93);");
    $V3643b863->F1417ca90($V0f14082c['logfile']);
    $V21d8a920->F215f9169();
}

If there is anything else you need here just let me know. I have been racking my brain over this for weeks.

Thanks in advance,
Krillin

This is also posted on my forums for tracking purposes.

Edited by Krillin
Thanked and signature with link to original post.
Link to comment
Share on other sites

Source

"Illegal string offset" most often means that someone wrote $value[offset] and $value is a string when the code thinks it was an array. Both of your errors reference parser-options, and looking at the code

$V0f14082c['parser-options']="";

that value is initially set up as a string. Change that to be an array and see what happens.

Please note that from here on, you cannot post large chunks of code - especially after you've made modifications to it. Given that link above, anyone can find the PHP source themselves for reference, so if you need to post any code then please include the smallest portion possible that you think is needed for someone to understand what's going on.

Link to comment
Share on other sites

14 hours ago, requinix said:

Source

"Illegal string offset" most often means that someone wrote $value[offset] and $value is a string when the code thinks it was an array. Both of your errors reference parser-options, and looking at the code


$V0f14082c['parser-options']="";

that value is initially set up as a string. Change that to be an array and see what happens.

Please note that from here on, you cannot post large chunks of code - especially after you've made modifications to it. Given that link above, anyone can find the PHP source themselves for reference, so if you need to post any code then please include the smallest portion possible that you think is needed for someone to understand what's going on.

Thank you for your reply, requinix!

I think I need to clarify something here, right now, for the record. It is cute that you think I used the "source" link that you provided. But that is NOT my source. My source is from myrddin's website from back on 11/23/2005. The source you linked to above is based on the V0.45 which doesn't even have the SQL injection vulnerability fixes, and much more which is in vsp-core_v0.46. In 2011 I fixed these issues and have been fixing them since as myrddin, the creator / author, has been unreachable since 2008. The date from my copies of v0.45 of VSP is 3/22/2005. I have been involved with vsp since 2004 myself and I have been keeping this going in myrddin's honor, not "evilru." Our codes are extremely different. They wrote that "source" based on 0.45, myrddin's last posted release, strictly for Q3A-XP excessive mod. I have been maintaining VSP since 2011, fixing errors and attempting to keep it up to code since 2011 with mysql and php newer released and coding requirements. That is what brought me here. So I do not know where you got the idea this was my source when there have been 4 additional version posted by me with fixes since 2011.

Now, this is really going to seem like a stupid question, but I am not a programmer, so where would this change need to be made? I am not sure where in the code the first time this value is used as to me it looks like it reads from down to up. To me it doesn't look like I replace line #979 or 1038. This is why I posted the entire function these run in. The vsp.php code is 67K. I promise, next time I will not post more than I need to as I thought I would post the entire function incase anyone needed more clarity on what it was doing. Being a old web designer from the 90's web pages always went from Top to Bottom. So hence why I need to ask this question.

So I am going to try applying this in vsp.php and toy with this a bit more before anyone answers in order to try to not waste anymore time and learn more!

Thanks again,
Krillin

Link to comment
Share on other sites

10 minutes ago, Krillin said:

I went in to add the change posted above only to find it is already in the function on line #957. It is below the line

The change you need to apply is to change that line so it's setting that variable up as an array rather than a string.

$V0f14082c['parser-options']="";

changes to

$V0f14082c['parser-options']=array();

 

Link to comment
Share on other sites

7 hours ago, Krillin said:

I went in to add the change posted above only to find it is already in the function on line #957. It is below the line:


global $V0f14082c; //line 956

I do not think it needs to be stated again?

"global" means that the function can access a variable defined globally (outside the function) by that name - because variables outside of functions are not automatically available inside of functions. That also means it applies only to the function it's being used inside of.
(It's also very bad practice to use, so don't try to learn from it, but this code is about 15 years old so...)

Link to comment
Share on other sites

7 hours ago, kicken said:

The change you need to apply is to change that line so it's setting that variable up as an array rather than a string.


$V0f14082c['parser-options']="";

changes to


$V0f14082c['parser-options']=array();

 

I am trying this now. But I see an addition "+2" at the end of a variable in the line I am replacing, so this tells me it is modifying this function for a reason, but I will give it a try. I will let you know here in just a bit as I make the changes on my development machine and test on a production server.

Thanks again,
Krillin

Link to comment
Share on other sites

13 minutes ago, requinix said:

"global" means that the function can access a variable defined globally (outside the function) by that name - because variables outside of functions are not automatically available inside of functions. That also means it applies only to the function it's being used inside of.
(It's also very bad practice to use, so don't try to learn from it, but this code is about 15 years old so...)

Your "source" is based on a 15 year old version. I have been updating VSP since 2011 when I took on this web module myself in 2011. I am working with a later version of vsp-core_v0.47, I had them up to v0.49, but I failed to test them and they did not work when I updated my PHP 5 to PHP 7 as I was required to do so with Apache Web Server on windows server. I ended up using my 2014 version of v0.47 as my core as this worked and brought up the "help" screen. Now I am bringing this core to current v0.50 for PHP 7/8 in keeping with my version history. I did not know how where to begin to fix this issue as there wasn't anything definitive that spoke to me about what I needed to do in order to address this offset. I had a hunch, but I was unclear as to what this section was trying to.

I am off to test the above. I will return.

Thanks again!
Krillin

Link to comment
Share on other sites

If all you changed was that one line kicken pointed out then apparently you've got more bugs.

But obfuscated code is terrible to read. Try fixing all the variable and function names to make more sense (find one that's easy to identify, rename it everywhere, repeat) and then giving the code a once-over to see that it seems right.

Link to comment
Share on other sites

15 minutes ago, requinix said:

If all you changed was that one line kicken pointed out then apparently you've got more bugs.

But obfuscated code is terrible to read. Try fixing all the variable and function names to make more sense (find one that's easy to identify, rename it everywhere, repeat) and then giving the code a once-over to see that it seems right.

Kicken was on the right track! I was fooling around with the different statements within this function. What I ended up doing was taking his line and ADDED it above line #979. Saved it, copied it to test it. And to my amazement IT WORKED!

The problem was solved by adding, not replacing.

			if (strcmp($V51d3ee44['argv'][$V865c0c0b], "-p")==0) {
                $V865c0c0b++;
                for ($V363b122c=$V865c0c0b;$V363b122c<$V51d3ee44['argc']-1;$V363b122c=$V363b122c+2) {
                    $V0f14082c['parser-options']=array();
                    $V0f14082c['parser-options'][$V51d3ee44['argv'][$V363b122c]]=$V51d3ee44['argv'][$V363b122c+1];
                }
                break;

I even tried replacing line #956, but that did not work either. So now the section looks like the code above and it solved the second 'trackID' issue as well.

FANTASTIC JOB guys. You guys helped me solve a problem I have been trying to solve for 3 - 4 weeks in just 36 hours. THANKS A MIL!

You Guys Rock!
Krillin

Link to comment
Share on other sites

Actually that's not going to work correctly. Maybe for the one thing you tested but not for everything.

This line of code.

$V0f14082c['parser-options']="";

That is what has to be replaced with

$V0f14082c['parser-options']=array();

Not added. Replaced. And the line that you added needs to be removed.

Link to comment
Share on other sites

I am currently rebuilding my player stats database from 2005 to today. It is going to take 4 days or so to complete this process with the new version vsp-core_v0.50. But my final word for now this is only testing with PHP 7.3.27. I still need to take a further leap to PHP 8.0.2 (at the time of this writing). But I am going to sit back and recover after a month of driving myself crazy as to why I could not come up with simple solution. You guys a thanked twice because there were two problems that were solved with one line of code needed to fix this issue. But I am saving 8.0.2 for another time, perhaps spring. By then they may be out with PHP 8.1! Right!

If I have anymore problems, I will be sure to reach out here again.

Once again, you guys our hero. Your help is very much appreceated.

Best Regards,
Krillin

Link to comment
Share on other sites

10 minutes ago, requinix said:

Actually that's not going to work correctly. Maybe for the one thing you tested but not for everything.

This line of code.




$V0f14082c['parser-options']="";

That is what has to be replaced with




$V0f14082c['parser-options']=array();

Not added. Replaced. And the line that you added needs to be removed.

Trust me. While I was waiting this afternoon I tried all sorts of options and they failed. I even tried swapping out 'argv' and 'argc' and that did not work either. So when I added the given array statement above the troubled line. I saw

Quote

processing D:\VSP\cs\Archive CS Logs 2005/L0910028.log
 - Verifying savestate
 - Hash did not match, assuming new log file
Analyzing game 0398 (05.06%) updating database...done

And I have not seen anything related to the savestate feature in a VERY long time now. I took a look in the /logdata/ folder and that hash for the files were present. So all is good once again.

Thank you!

Edited by Krillin
Link to comment
Share on other sites

46 minutes ago, Krillin said:

Trust me.

I trust code, and the code you created is incorrect. You might discover it soon, or you might discover it later, or you might not even discover it at all, but that doesn't change the fact that it is factually wrong.

But whatever. Not my site or my data. Have fun.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.