better download handling #8
[rock.divinelegy.git] / Controllers / FileController.php
1 <?php
2
3 namespace Controllers;
4
5 use Controllers\IDivineController;
6 use Services\Http\IHttpRequest;
7 use Services\Http\IHttpResponse;
8 use Services\IUserSession;
9 use Services\IStatusReporter;
10 use Services\IUserQuota;
11 use Services\IConfigManager;
12 use Domain\Entities\IDownloadFactory;
13 use DataAccess\IFileRepository;
14 use DataAccess\IDownloadRepository;
15
16 class FileController implements IDivineController
17 {
18 private $_fileRepository;
19 private $_response;
20 private $_request;
21 private $_downloadRepository;
22 private $_downloadFactory;
23 private $_userSession;
24 private $_userQuota;
25 private $_statusReporter;
26 private $_configManager;
27
28 public function __construct(
29 IHttpRequest $request,
30 IHttpResponse $response,
31 IFileRepository $repository,
32 IDownloadFactory $downloadFactory,
33 IDownloadRepository $downloadRepository,
34 IUserSession $userSession,
35 IUserQuota $userQuota,
36 IStatusReporter $statusReporter,
37 IConfigManager $configManager
38 ) {
39 $this->_request = $request;
40 $this->_response = $response;
41 $this->_fileRepository = $repository;
42 $this->_downloadRepository = $downloadRepository;
43 $this->_downloadFactory = $downloadFactory;
44 $this->_userSession = $userSession;
45 $this->_userQuota = $userQuota;
46 $this->_statusReporter = $statusReporter;
47 $this->_configManager = $configManager;
48 }
49
50 public function indexAction() {
51 ;
52 }
53
54 // list simfiles
55 public function serveBannerAction($hash)
56 {
57 //TODO: This DOES NOT check that the file the request is asking for is _actually_
58 //the file we are server. This is because at this stage banners cannot change, we should
59 //be careful maybe.
60 if($this->_request->getHeader('HTTP_IF_MODIFIED_SINCE'))
61 {
62 $this->_response->setHeader("HTTP/1.1 304 Not Modified", 'Nice meme!');
63 } else {
64 $file = $this->_fileRepository->findByHash($hash);
65 if($hash == 'default') $this->serveDefaultBanner();
66 if(!$file) $this->notFound();
67
68 $matches = glob(realpath($this->_configManager->getDirective('filesPath') . '/' . $file->getPath()) . '/' . $file->getHash() . '.*');
69 $match = reset($matches);
70
71 $this->_response->setHeader('Content-Type', $file->getMimetype())
72 ->setHeader('Content-Length', $file->getSize())
73 ->setHeader('etag', $file->getHash())
74 ->setHeader('last-modified', gmdate("D, d M Y H:i:s", $file->getUploadDate()) . " GMT")
75 ->setHeader('cache-control', 'max-age=-1')
76 ->setBody(file_get_contents($match));
77 }
78
79 $this->_response->sendResponse();
80 }
81
82 private function serveDefaultBanner()
83 {
84 //XXX: As above
85 if($this->_request->getHeader('HTTP_IF_MODIFIED_SINCE'))
86 {
87 $this->_response->setHeader("HTTP/1.1 304 Not Modified", 'Nice meme!');
88 } else {
89 $path = $this->_configManager->getDirective('filesPath') . '/banners/default.png';
90 $file = realpath($path);
91 $this->_response->setHeader('Content-Type', 'image/png')
92 ->setHeader('Content-Length', filesize($file))
93 ->setBody(file_get_contents($file))
94 ->setHeader('etag', md5_file($file))
95 ->setHeader('last-modified', gmdate("D, d M Y H:i:s", filemtime($file)) . " GMT")
96 ->setHeader('cache-control', 'max-age=-1')
97 ->sendResponse();
98 }
99
100 exit();
101 }
102
103 public function serveSimfileOrPackAction($hash)
104 {
105 $file = $this->_fileRepository->findByHash($hash);
106 $quotaRemaining = $this->_userQuota->getCurrentUserQuotaRemaining();
107
108 if(!$file) $this->notFound();
109 if(!$quotaRemaining) $this->notAuthorised();
110 if($quotaRemaining < $file->getSize()) $this->notEnoughQuota();
111
112 // TODO: Builder?
113 $download = $this->_downloadFactory->createInstance($this->_userSession->getCurrentUser(),
114 $file,
115 time(),
116 $this->_request->getIp());
117
118 $this->_downloadRepository->save($download);
119
120 $zip = $this->_configManager->getDirective('filesPath') . '/' . $file->getPath() . '/' . $file->getHash() . '.zip';
121 $this->_response->setHeader('Content-Type', $file->getMimetype())
122 ->setHeader('Content-Length', $file->getSize())
123 ->setHeader('Content-Disposition', 'filename="' . $file->getFileName() . '";')
124 ->download($zip);
125 exit();
126 }
127
128 private function notFound()
129 {
130 $this->_response->setHeader('HTTP/1.0 404 Not Found', 'Nothing to see here')
131 ->setBody('Move along.')
132 ->sendResponse();
133 exit();
134 }
135
136 private function notAuthorised()
137 {
138 $this->_response->setHeader('Content-Type', 'application/json')
139 ->setBody($this->_statusReporter->error('You must be authenticated to download files')->json())
140 ->sendResponse();
141 exit();
142 }
143
144 private function notEnoughQuota()
145 {
146 $this->_response->setHeader('Content-Type', 'application/json')
147 ->setBody($this->_statusReporter->error('You don\'t have enough quota remaining for this file.')->json())
148 ->sendResponse();
149 exit();
150 }
151 }