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

Revision 2688, 4.9 KB checked in by lowjoel, 2 years ago (diff)

Factor out the Stack Frame parsing code to the GetStackFrameInformation? function.

Line 
1<?php
2if (empty($_POST) || empty($_POST['action']))
3    exit;
4
5ob_start();
6require('../Database.php');
7
8function GetFunctionNameFromStackTrace($line)
9{
10    $result = GetStackFrameInformation($line);
11    return $result->function;
12}
13
14function GetStackFrameInformation($line)
15{
16    //at Eraser.Program.OnGUIInitInstance(Object sender) in D:\Development\Projects\Eraser 6.2\Eraser\Program.cs:line 191
17    $matches = array();
18    $function = $file = $line = null;
19    if (preg_match('/^([^   ]+) (.*) ([^    ]+) (.*):([^    ]+) ([0-9]+)/', $line, $matches))
20    {
21        $function = $matches[2];
22        $file = $matches[4];
23        $line = intval($matches[6]);
24    }
25    else if (preg_match('/^([^  ]+) (.*)/', $line, $matches))
26    {
27        $function = $matches[2];
28    }
29
30    return (object)array('function' => $function, 'file' => $file, 'line' => $line);
31}
32
33function QueryStatus($stackTrace)
34{
35    //Check that a similar stack trace hasn't been uploaded.
36    $status = 'exists';
37    $pdo = new Database();
38    foreach ($stackTrace as $exceptionDepth => $exception)
39    {
40        if ($status != 'exists')
41            break;
42
43        $stackFrames = '';
44        foreach ($exception as $stackIndex => $stackFrame)
45        {
46            //Ignore the exception key; that stores the exception type.
47            if ($stackIndex == 'exception')
48                continue;
49
50            $stackFrames .= sprintf('(StackFrameIndex=%d AND Function=%s) OR ',
51                $stackIndex, $pdo->quote(GetFunctionNameFromStackTrace($stackFrame)));
52        }
53       
54        if (empty($stackFrames))
55            continue;
56       
57        //Query for the list of exceptions containing the given functions
58        $statement = $pdo->prepare(sprintf('SELECT DISTINCT(BlackBox_Exceptions.ID) FROM BlackBox_StackFrames
59            INNER JOIN BlackBox_Exceptions ON BlackBox_StackFrames.ExceptionID=BlackBox_Exceptions.ID
60            WHERE (%s) AND ExceptionDepth=? AND ExceptionType=?',
61            substr($stackFrames, 0, strlen($stackFrames) - 4)));
62        $statement->bindParam(1, $exceptionDepth);
63        $statement->bindParam(2, $exception['exception']);
64        $statement->execute();
65
66        if ($statement->rowCount() == 0)
67            $status = 'new';
68    }
69   
70    header('Content-Type: application/xml');
71    printf('<?xml version="1.0"?>
72<crashReport status="%s" />', htmlspecialchars($status));
73}
74
75function Upload($stackTrace, $crashReport)
76{
77    $pdo = new Database();
78    $pdo->beginTransaction();
79
80    $statement = $pdo->prepare('INSERT INTO BlackBox_Reports SET IPAddress=?');
81    $statement->bindParam(1, sprintf('%u', ip2long($_SERVER['REMOTE_ADDR'])));
82    try
83    {
84        $statement->execute();
85    }
86    catch (PDOException $e)
87    {
88        throw new Exception('Could not insert crash report into Reports table', null, $e);
89    }
90
91    $reportId = $pdo->lastInsertId();
92    $exceptionInsert = $pdo->prepare('INSERT INTO BlackBox_Exceptions
93        SET ReportID=?, ExceptionType=?, ExceptionDepth=?');
94    $exceptionInsert->bindParam(1, $reportId);
95    $stackFrameInsert = $pdo->prepare('INSERT INTO BlackBox_StackFrames SET
96        ExceptionID=?, StackFrameIndex=?, Function=?, File=?, Line=?');
97    foreach ($stackTrace as $exceptionDepth => $exception)
98    {
99        $exceptionInsert->bindParam(2, $exception['exception']);
100        $exceptionInsert->bindParam(3, $exceptionDepth);
101        try
102        {
103            $exceptionInsert->execute();
104        }
105        catch (PDOException $e)
106        {
107            throw new Exception('Could not insert exception into Exceptions table', null, $e);
108        }
109       
110        $exceptionId = $pdo->lastInsertId();
111        foreach ($exception as $stackIndex => $stackFrame)
112        {
113            //Ignore the exception key; that stores the exception type.
114            if ((string)$stackIndex == 'exception')
115                continue;
116           
117            $stackFrameInfo = GetStackFrameInformation($stackFrame);
118
119            $stackFrameInsert->bindParam(1, $exceptionId);
120            $stackFrameInsert->bindParam(2, $stackIndex);
121            $stackFrameInsert->bindParam(3, $stackFrameInfo->function);
122            $stackFrameInsert->bindParam(4, $stackFrameInfo->file);
123            $stackFrameInsert->bindParam(5, $stackFrameInfo->line);
124            try
125            {
126                $stackFrameInsert->execute();
127            }
128            catch (PDOException $e)
129            {
130                throw new Exception('Could not insert stack frame into Stack Frames table', null, $e);
131            }
132        }
133    }
134   
135    $pdo->commit();
136
137    //Move the temporary file to out dumps folder for later inspection
138    $localName = $crashReport['name'];
139    $lastDot = strrpos($localName, '.');
140    if ($lastDot !== false)
141        $localExt = substr($localName, strrpos($localName, '.') + 1);
142    else
143        $localExt = 'bz2';
144    if (!move_uploaded_file($crashReport['tmp_name'], 'dumps/' . $reportId . '.tar.' . $localExt))
145        throw new Exception('Could not store crash dump onto server.');
146}
147
148try
149{
150    switch ($_POST['action'])
151    {
152        case 'status':
153            if (empty($_POST['stackTrace']))
154                exit;
155            QueryStatus($_POST['stackTrace']);
156            break;
157   
158        case 'upload':
159            if (empty($_FILES) || empty($_POST['stackTrace']))
160                exit;
161            Upload($_POST['stackTrace'], $_FILES['crashReport']);
162            break;
163    }
164}
165catch (Exception $e)
166{
167    ob_end_clean();
168    header('HTTP/1.1 500 Internal Server Error');
169    printf('<?xml version="1.0"?>
170<error>%s</error>', htmlspecialchars($e->getMessage()));
171}
172?>
Note: See TracBrowser for help on using the repository browser.