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

Revision 1632, 8.2 KB checked in by lowjoel, 4 years ago (diff)

Suggest the name of the download when it is requested, instead of the name of the file on disk.

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