1

I am having quite the challenge. I have my function where() which tracks where users are visiting on the site, and takes the script filename and provides a description and inserts into database.

The script was working great, until recently, and unaware of the failure of this function after a recent minor update from MySQL 5.6.40 to 5.6.47

I am not sure if that had anything to do with it, but I discovered days later that it was not working anymore.

Our function:

function where($scriptname = "index", $userid, $update=1){
    if (!is_valid_id($userid))
        die;

    if (preg_match("/details.php/i", $scriptname))
        $where = "Browsing File Details (ID $_GET[id])";
    elseif (preg_match("/files.php/i", $scriptname))
        $where = "Browsing Files";
    elseif (preg_match("/account-info.php/i", $scriptname))
        $where = "Browsing Account Info (ID $_GET[id])";
    elseif (preg_match("/upload.php/i", $scriptname))
        $where = "Uploading File";
    elseif (preg_match("/account.php/i", $scriptname))
        $where = "Browsing User Control Panel";
    elseif (preg_match("/search.php/i", $scriptname))
        $where = "Searching For Files";
    elseif (preg_match("/forums.php/i", $scriptname))
        $where = "Viewing Forums";
    elseif (preg_match("/index.php/i", $scriptname))
        $where = "Browsing Homepage";
    elseif (preg_match("/mailbox.php/i", $scriptname))
        $where = "Viewing Messages";
    elseif (preg_match("/comments.php/i", $scriptname))
        $where = "Viewing Comments";
    elseif (preg_match("/recover.php/i", $scriptname))
        $where = "Recovering Account";
    elseif (preg_match("/bookmarks.php/i", $scriptname))
        $where = "Viewing Bookmarks";
    elseif (preg_match("/getfile.php/i", $scriptname))
        $where = "Downloaded File (ID $_GET[id])";
    elseif (preg_match("/faq.php/i", $scriptname))
        $where = "Reading FAQ Page";
    elseif (preg_match("/friends.php/i", $scriptname))
        $where = "Viewing Friends";
    elseif (preg_match("/admin.php/i", $scriptname))
        $where = "Managing Admin Panel";
    else
        $where = "Unknown Location";

    if ($update) {
        // Worked until a few days ago. No site changes were made prior for quite some time. 
        //$query = sprintf("UPDATE users SET page=".sqlesc($where)." WHERE id ='%s'", mysql_real_escape_string($userid)); 
        // Now using line below, which does insert into row if I use my own variable. 
        $query = "UPDATE users SET last_access='" . get_date_time() . "', page=" . sqlesc($where) . " WHERE id=" . $userid;
        $result = SQL_Query_exec($query);
    }
        return $where;
}

Now, I have tried the following code to narrow it down to what is causing it. Currently, the function above only inserts

Unknown Location

to the Database, no matter what page is viewed.

I got it down to this:

$stringtest = "This inserts into database!";
$query = "UPDATE users SET last_access='" . get_date_time() . "', page=" . sqlesc($stringtest) . " WHERE id=" . $userid;

This works great, however it is not passing any of the $where conditions.

I've tried varies regular expressions for filename matching to no avail.

Any idea what I'm doing wrong?

Thanks in advance!

6
  • 1
    You should learn to use prepared statements rather than concatenating strings into the SQL. Commented Feb 20, 2020 at 0:30
  • 4
    "Unknown Location" happens before any SQL is done. Debug what $scriptname is passed to this function. Commented Feb 20, 2020 at 0:31
  • Put var_dump($scriptname, $where) after the if/else. Commented Feb 20, 2020 at 0:33
  • @Barmar - I have used your suggestion var_dump and this is what is produced: string(55) "/usr/local/www/htdocs/details.php" string(33) "Browsing File Details (ID 193)" Not quite sure what to do with this. Seems to be technically working, but will not update row? Commented Feb 20, 2020 at 0:44
  • 1
    I don't know why the first preg_match() isn't matching that name. Commented Feb 20, 2020 at 0:47

2 Answers 2

1

For the SQL part use prepared statements, as noted above.

Assuming, the $scriptname holds filename, without extension, and not the absolute path, and based on the code provided I don't see great need for preg_match() there. Just simple switch ... case would do.

Even better, if you want to have a sort of manageable list of locations with descriptions (you reuse them every time anyway), you could had associative array (could be returned by a separate function) like below and do as follows:

$locations = array(
  'index' => 'Browsing Homepage', 
  'forums' => 'Browsing Homepage,
  //  and so on for all of your files
);

// And to get the description - assuming case matters, otherwise use strtolower()
$desc = isset($locations[$scriptname]) ? $locations[$scriptname] : 'Unknown Location';
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, I will rewrite the function and use prepared statements now. The function I posted is not efficient and I think can be achieved by returning basename PHP_SELF to the row by userid. Less mess, and I can use cases for filenames
Not sure what are the requirements for the reporting here, but maybe it is better saving full path of the script - no extra processing at all. The more visitors you have the more calls you will have to the log method. Keeping log action fast is vital. On the other hand reporting happens occasionally and for that you can have more processing time. Another script can interpret your logs. Make script paths to be associated with any type of information - single line of text or an object - and present this info in your reports later. Just like in the example above.
I've still had little to no luck. I can properly resolve filenames with this: if (basename("details.php", $where)) $where = "Viewing Details"; But it will only use the first match in the whole block, the other pages do not report and it defaults to that details page. I've tried maybe 5 different functions and I wish I knew what I'm doing wrong here...
How do you get the script name? Also, "." has special meaning in regex, you have to escape it. AND - you really have to simplify things - regex is not called for here.
I have since switch to a array solution for this with better checking, the old code was on its way out.
0

I noticed your default value for $scriptname is "index". I presume this references "index.php"? Whereas your matching pattern is also looking for the file extension. (By the way, the un-escaped . doesn't mean a literal ".". It's a RegEx rule for 'any one character'. So yeah, it'll work, but kind of by accident.)

What kind of values are you passing in? Try die/dumping the value of $scriptname within that function, before the comparisons are run, as a sanity-check to verify that the expected kind of input is being received. It could be you're seeing legit, if only unexpected, failures.

4 Comments

I’m passing in $userid which sends over the current users ID logged in, the commented line was the working line. I did run var_dump($scriptname, $where); after ‘else’ and the output reveals string(55) "/usr/local/www/htdocs/details.php" string(33) "Browsing File Details (ID 193)
$scriptname = “index” has no effect, it works the same with just $scriptname, I tried appending basename() to $scriptname in var_dump, and have a single file name but it doesn’t do anything in the elseif block. I see inserts of a direct path to the error 404 page in the database on my other attempts playing with the output of $where
Cool! So the problem isn't in the snippet you posted here. It's that whatever is taking to that function is sending full filepaths instead of filenames. Either start debugging the caller, or apply $scriptname = basename($scriptname); to the top of the function. Good luck!
Thanks bud, I appreciate it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.