source: trunk/website/scripts/blackbox/upload.php @ 1672

Revision 1672, 4.3 KB checked in by lowjoel, 5 years ago (diff)
  • Fixed parsing of stack frames after changing the regex
  • Include the very first stack frame - comparing int to string caused the string 'exception' to be cast to int 0, hence the equality was true and the comparison skipped for element 0
Line 
1<?php
2if (empty($_POST) || empty($_POST['action']))
3    exit;
4
5ob_start();
6require('../database.php');
7
8function GetFunctionNameFromStackTrace($line)
9{
10    $matches = array();
11    if (preg_match('/^([^   ]+) (.*) ([^    ]+) (.*):([^    ]+) ([0-9]+)/', $line, $matches))
12    {
13    }
14    else if (preg_match('/^([^  ]+) (.*)/', $line, $matches))
15    {
16    }
17   
18    return $matches[2];
19}
20
21function QueryStatus($stackTrace)
22{
23    //Check that a similar stack trace hasn't been uploaded.
24    $status = 'exists';
25    foreach ($stackTrace as $exceptionDepth => $exception)
26    {
27        if ($status != 'exists')
28            break;
29
30        $stackFrames = '';
31        foreach ($exception as $stackIndex => $stackFrame)
32        {
33            //Ignore the exception key; that stores the exception type.
34            if ($stackIndex == 'exception')
35                continue;
36
37            $stackFrames .= sprintf('(StackFrameIndex=%d AND Function=\'%s\') OR ',
38                $stackIndex, mysql_real_escape_string(GetFunctionNameFromStackTrace($stackFrame)));
39        }
40       
41        if (empty($stackFrames))
42            continue;
43       
44        //Query for the list of exceptions containing the given functions
45        $query = mysql_query(sprintf('SELECT DISTINCT(BlackBox_Exceptions.ID) FROM BlackBox_StackFrames
46            INNER JOIN BlackBox_Exceptions ON BlackBox_StackFrames.ExceptionID=BlackBox_Exceptions.ID
47            WHERE (%s) AND ExceptionDepth=%d AND ExceptionType=\'%s\'',
48            substr($stackFrames, 0, strlen($stackFrames) - 4), $exceptionDepth,
49            mysql_real_escape_string($exception['exception'])));
50       
51        if (mysql_num_rows($query) == 0)
52            $status = 'new';
53    }
54   
55    header('Content-Type: application/xml');
56    printf('<?xml version="1.0"?>
57<crashReport status="%s" />', htmlspecialchars($status));
58}
59
60function Upload($stackTrace, $crashReport)
61{
62    mysql_query('BEGIN TRANSACTION');
63    mysql_query(sprintf('INSERT INTO BlackBox_Reports SET IPAddress=%u', ip2long($_SERVER['REMOTE_ADDR'])));
64    if (mysql_affected_rows() != 1)
65        throw new Exception('Could not insert crash report into Reports table: ' . mysql_error());
66
67    $reportId = mysql_insert_id();
68    foreach ($stackTrace as $exceptionDepth => $exception)
69    {
70        mysql_query(sprintf('INSERT INTO BlackBox_Exceptions SET ReportID=%d, ExceptionType=\'%s\', ExceptionDepth=%d',
71            $reportId, mysql_real_escape_string($exception['exception']), $exceptionDepth));
72        if (mysql_affected_rows() != 1)
73            throw new Exception('Could not insert exception into Exceptions table: ' . mysql_error());
74
75        $exceptionId = mysql_insert_id();
76        foreach ($exception as $stackIndex => $stackFrame)
77        {
78            //Ignore the exception key; that stores the exception type.
79            if ((string)$stackIndex == 'exception')
80                continue;
81           
82            //at Eraser.Program.OnGUIInitInstance(Object sender) in D:\Development\Projects\Eraser 6.2\Eraser\Program.cs:line 191
83            $matches = array();
84            $function = $file = $line = null;
85            if (preg_match('/^([^   ]+) (.*) ([^    ]+) (.*):([^    ]+) ([0-9]+)/', $stackFrame, $matches))
86            {
87                $function = $matches[2];
88                $file = $matches[4];
89                $line = intval($matches[6]);
90            }
91            else if (preg_match('/^([^  ]+) (.*)/', $stackFrame, $matches))
92            {
93                $function = $matches[2];
94            }
95           
96            mysql_query(sprintf('INSERT INTO BlackBox_StackFrames SET
97                ExceptionID=%d, StackFrameIndex=%d, Function=\'%s\', File=%s, Line=%s',
98                $exceptionId, $stackIndex, mysql_real_escape_string($function),
99                empty($file) ? 'null' : sprintf('\'%s\'', mysql_real_escape_string($file)),
100                $line == null ? 'null' : intval($line)));
101           
102            if (mysql_affected_rows() != 1)
103                throw new Exception('Could not insert stack frame into Stack Frames table: ' . mysql_error());
104        }
105    }
106   
107    mysql_query('COMMIT');
108   
109    //Move the temporary file to out dumps folder for later inspection
110    if (!move_uploaded_file($crashReport['tmp_name'], 'dumps/' . $reportId . '.tbz'))
111        throw new Exception('Could not store crash dump onto server.');
112}
113
114try
115{
116    switch ($_POST['action'])
117    {
118        case 'status':
119            if (empty($_POST['stackTrace']))
120                exit;
121            QueryStatus($_POST['stackTrace']);
122            break;
123   
124        case 'upload':
125            if (empty($_FILES) || empty($_POST['stackTrace']))
126                exit;
127            Upload($_POST['stackTrace'], $_FILES['crashReport']);
128            break;
129    }
130}
131catch (Exception $e)
132{
133    ob_end_clean();
134    header('HTTP/1.1 500 Internal Server Error');
135    printf('<?xml version="1.0"?>
136<error>%s</error>', htmlspecialchars($e->getMessage()));
137}
138?>
Note: See TracBrowser for help on using the repository browser.