source: trunk/website/scripts/downloads.php @ 1631

Revision 1631, 8.0 KB checked in by lowjoel, 5 years ago (diff)
  • Optimized the selection algorithm for picking builds from the builds table
  • If we can't find a build by the given branch and revision, then we should throw an exception. The handling of new builds is now done in the Build::Get function
  • Define the Build::BuildExists? function to check whether a build exists/has been created
  • Build::InsertBuild? now accepts a path to the revision so it can accept files with the revision as its filename
Line 
1<?php
2require('database.php');
3
4class Download
5{
6    protected $ID;
7
8    public function Download($downloadID)
9    {
10        $query = mysql_query(sprintf('SELECT COUNT(DownloadID) FROM downloads WHERE DownloadID=%d',
11            intval($downloadID)));
12        if (($row = mysql_fetch_row($query)) === false || $row[0] == 0)
13            throw new Exception(sprintf('Could not find download %d', $downloadID));
14
15        $this->ID = $downloadID;
16    }
17   
18    public function InitiateDownload()
19    {
20        //Register the download
21        mysql_query(sprintf('INSERT INTO download_log (DownloadID) VALUES (%d)', $this->ID));
22       
23        if (preg_match('/http(s{0,1}):\/\/(.*)/', $this->Link))
24            header('location: ' . $this->Link);
25        else if (substr($this->Link, 0, 1) == '?')
26            Download::DownloadFile(substr($this->Link, 1));
27        else
28            throw new Exception('Unknown download link');
29    }
30   
31    public function __get($varName)
32    {
33        $sql = sprintf('SELECT %%s FROM downloads WHERE DownloadID=%d', $this->ID);
34        switch ($varName)
35        {
36            case 'ID':
37                return $this->ID;
38
39            case 'Downloads':
40                $sql = sprintf('SELECT Downloads FROM download_statistics WHERE DownloadID=%d', $this->ID);
41                break;
42
43            case 'Name':
44            case 'Released':
45            case 'Superseded':
46            case 'Link':
47                $sql = sprintf($sql, $varName);
48                break;
49        }
50       
51        if (empty($sql))
52            return null;
53       
54        $query = mysql_query($sql);
55        $row = $query ? mysql_fetch_row($query) : null;
56        $result = $row ? $row[0] : null;
57       
58        if ($result !== null)
59            switch ($varName)
60            {
61                case 'Downloads':
62                    $result = intval($result);
63                    break;
64                case 'Released':
65                    $result = MySqlToPhpTimestamp($result);
66                    break;
67            }
68       
69        return $result;
70    }
71
72    public function __set($varName, $value)
73    {
74        $sql = sprintf('UPDATE downloads SET %%s=%%s WHERE DownloadID=%d', $this->ID);
75        switch ($varName)
76        {
77            case 'Superseded':
78                $sql = sprintf($sql, $varName, intval($value));
79                break;
80            default:
81                return;
82        }
83       
84        if (empty($sql))
85            return;
86        mysql_query($sql);
87    }
88   
89    private static function DownloadFile($path, $visibleName = null)
90    {
91        $downloadFolder = dirname(__FILE__) . '/../downloads/';
92        $visibleName = $visibleName == null ? basename($path) : $visibleName;
93
94        header('Content-Type: application/octet-stream');
95        header('Content-Length: ' . filesize($downloadFolder . $path));
96        if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false)
97        {
98            //IE browser
99            header('Content-Disposition: inline; filename="' . $visibleName . '"');
100            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
101            header('Pragma: public');
102        }
103        else
104        {
105            header('Content-Disposition: attachment; filename="' . $visibleName . '"');
106            header('Pragma: no-cache');
107        }
108
109        readfile($downloadFolder . $path);
110    }
111};
112
113class Build extends Download
114{
115    public function Build($branch, $revision)
116    {
117        $query = mysql_query(sprintf('SELECT DownloadID FROM builds WHERE
118                Branch=\'%s\' AND Revision=%d',
119            mysql_real_escape_string($branch), intval($revision)));
120       
121        //See if the build already has a database entry
122        if (($row = mysql_fetch_row($query)) === false || !$row[0])
123        {
124            throw new Exception('Build does not exist');
125        }
126        else
127        {
128            $this->ID = intval($row[0]);
129
130            //Check that the folder has not been removed. This may indicate supersedence.
131            $downloadFolder = dirname(__FILE__) . '/../downloads/';
132            if (!file_exists($downloadFolder . substr($this->Link, 1)))
133                $this->Superseded = 1;
134        }
135    }
136   
137    public static function Get()
138    {
139        $result = array();
140        $builds = array('Eraser5' => 'Eraser 5', 'Eraser6' => 'Eraser 6.0', 'Eraser6.2' => 'Eraser 6.2');
141        foreach ($builds as $branchName => $buildName)
142        {
143            $revisions = opendir(Build::GetPath($branchName));
144            $result[$buildName] = array();
145
146            while (($revision = readdir($revisions)) !== false)
147            {
148                if ($revision == '.' || $revision == '..')
149                    continue;
150               
151                $pathInfo = pathinfo($revision);
152                $revisionID = intval(substr($pathInfo['filename'], 1));
153                if (Build::BuildExists($branchName, $revisionID))
154                {
155                    $result[$buildName][] = new Build($branchName, $revisionID);
156                }
157                else
158                {
159                    $result[$buildName][] = Build::GetBuildFromID(
160                        Build::InsertBuild($branchName, $revisionID,
161                            Build::GetPath($branchName, $revision)));
162                }
163            }
164        }
165       
166        return $result;
167    }
168   
169    public static function BuildExists($branch, $revision)
170    {
171        $query = mysql_query(sprintf('SELECT DownloadID FROM builds WHERE
172                Branch=\'%s\' AND Revision=%d',
173            mysql_real_escape_string($branch), intval($revision)));
174        return mysql_num_rows($query) == 1;
175    }
176   
177    public static function GetBuildFromID($downloadID)
178    {
179        $query = mysql_query(sprintf('SELECT * FROM builds WHERE DownloadID=%d', intval($downloadID)));
180        if (($row = mysql_fetch_array($query)) === false || !$row[0])
181            return null;
182
183        return intval($row[0]) ? new Build($row['Branch'], $row['Revision']) : null;
184    }
185   
186    public function __get($varName)
187    {
188        $sql = sprintf('SELECT %%s FROM builds WHERE DownloadID=%d', $this->ID);
189        switch ($varName)
190        {
191            case 'Revision':
192            case 'Branch':
193                $sql = sprintf($sql, $varName);
194                break;
195
196            default:
197                return parent::__get($varName);
198        }
199       
200        $query = mysql_query($sql);
201        $row = $query ? mysql_fetch_row($query) : null;
202       
203        return $row ? $row[0] : null;
204    }
205   
206    private static function InsertBuild($branch, $revision, $buildPath)
207    {
208        //Find the binary that users will get to download.
209        $installerPath = null;
210       
211        //If $buildPath is a directory, it contains the installer.
212        if (is_dir($buildPath))
213        {
214            $directory = opendir($buildPath);
215           
216            while (($file = readdir($directory)) !== false)
217            {
218                $filePath = $buildPath . '/' . $file;
219                if (is_file($filePath))
220                {
221                    $pathInfo = pathinfo($filePath);
222                    if ($pathInfo['extension'] == 'exe')
223                    {
224                        $installerPath = sprintf('builds/%s/r%s/%s', $branch, $revision, $file);
225                        break;
226                    }
227                }
228            }
229        }
230        //If $buildPath.exe is a file, it's the installer we want.
231        else if (is_file($buildPath))
232        {
233            $installerPath = sprintf('builds/%s/r%s', $branch, basename($buildPath));
234        }
235
236        if (empty($installerPath))
237        {
238            //It is a build in progress, don't create anything.
239            throw new Exception(sprintf('Build %s r%d is incomplete.', $branch, $revision));
240        }
241       
242        //Insert the build into the database.
243        mysql_query('START TRANSACTION');
244        mysql_query(sprintf('INSERT INTO downloads (Name, Released, `Type`, Version, PublisherID, Architecture, Filesize, Link)
245                VALUES (
246                    \'%1$s r%2$d\', \'%4$s\' , \'build\', \'r%2$d\', 1, \'any\', %3$d, \'?%5$s\'
247                )',
248            mysql_real_escape_string($branch), intval($revision), filesize($installerPath),
249            PhpToMySqlTimestamp(filemtime($buildPath)), mysql_real_escape_string($installerPath)))
250                or die(mysql_error());
251        mysql_query(sprintf('INSERT INTO builds (DownloadID, Branch, Revision)
252                VALUES (
253                    LAST_INSERT_ID(), \'%s\', %d
254                )',
255            mysql_real_escape_string($branch), intval($revision)))
256                or die(mysql_error());
257
258        if (!mysql_affected_rows())
259            throw new Exception(sprintf('Could not create new build %s r%d. MySQL Error: %s', $path, $revision, mysql_error()));
260        $buildId = mysql_insert_id();
261       
262        mysql_query('COMMIT');
263       
264        //Ensure that only 3 builds are not superseded at any one time.
265        mysql_query('START TRANSACTION');
266        mysql_query(sprintf('UPDATE downloads SET Superseded=1
267            WHERE DownloadID IN (
268                SELECT DownloadID FROM builds where Branch=\'%s\'
269            )',
270            mysql_real_escape_string($branch)));
271        mysql_query(sprintf('UPDATE downloads SET Superseded=0
272            WHERE DownloadID IN (
273                SELECT DownloadID FROM builds where Branch=\'%s\'
274            )
275            ORDER BY DownloadID DESC
276            LIMIT 3', mysql_real_escape_string($branch)));
277        mysql_query('COMMIT');
278        return $buildId;
279    }
280   
281    private static function GetPath($path, $revision = null)
282    {
283        return sprintf('%s/../downloads/builds/%s%s', dirname(__FILE__), $path,
284            $revision === null ? '' : sprintf('/r%s', $revision));
285    }
286};
287?>
Note: See TracBrowser for help on using the repository browser.