Passed
Pull Request — master (#74)
by
unknown
03:52
created

GetFileController   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Importance

Changes 12
Bugs 0 Features 0
Metric Value
dl 0
loc 234
rs 10
c 12
b 0
f 0
wmc 27

4 Methods

Rating   Name   Duplication   Size   Complexity  
A isForbidden() 0 5 3
A sanitizeFilename() 0 11 1
A buildMetsXml() 0 23 2
D attachmentAction() 0 168 21
1
<?php
2
namespace EWW\Dpf\Controller;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
/**
18
 * API to return METS dissemination and Attachments from Fedora.
19
 * Also renders METS XML for preview. Structure of the URIs totally
20
 * depend on proper RealURL configuration.
21
 *
22
 * Example:
23
 *
24
 * 1. METS from Fedora
25
 *   http://localhost/api/qucosa:1234/mets/
26
 *
27
 *   This always returns METS which is supplemented with additional information.
28
 *   The embedded MODS record is not the original MODS as it is stored in the
29
 *   repository datastream.
30
 *
31
 * 2. Attachment from Fedora
32
 *   http://localhost/api/qucosa:1234/attachment/ATT-0/
33
 *
34
 * 3. METS from Kitodo.Publication (this extension)
35
 *   http://localhost/api/3/preview/
36
 *
37
 * 4. DataCite from Kitodo.Publication (this extension)
38
 *
39
 * @author    Alexander Bigga <[email protected]>
40
 * @author    Ralf Claussnitzer <[email protected]>
41
 * @author    Florian Rügamer <[email protected]>
42
 */
43
44
use TYPO3\CMS\Core\Utility\GeneralUtility;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Core\Utility\GeneralUtility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
45
46
/**
47
 * GetFileController
48
 */
49
class GetFileController extends \EWW\Dpf\Controller\AbstractController
50
{
51
52
    /**
53
     * documentRepository
54
     *
55
     * @var \EWW\Dpf\Domain\Repository\DocumentRepository
56
     * @inject
57
     */
58
    protected $documentRepository;
59
60
    /**
61
     * clientConfigurationManager
62
     *
63
     * @var \EWW\Dpf\Configuration\ClientConfigurationManager
64
     * @inject
65
     */
66
    protected $clientConfigurationManager;
67
68
    public function attachmentAction()
69
    {
70
71
        $piVars = GeneralUtility::_GP('tx_dpf'); // get GET params from powermail
72
73
        $fedoraHost = $this->clientConfigurationManager->getFedoraHost();
74
75
        if (isForbidden($piVars['action'])) {
0 ignored issues
show
Bug introduced by
The function isForbidden was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        if (/** @scrutinizer ignore-call */ isForbidden($piVars['action'])) {
Loading history...
76
            $this->response->setStatus(403);
77
            return 'Forbidden';
78
        }
79
80
        switch ($piVars['action']) {
81
            case 'mets':
82
                $path = rtrim('http://' . $fedoraHost,"/").'/fedora/objects/'.$piVars['qid'].'/methods/qucosa:SDef/getMETSDissemination?supplement=yes';
83
                break;
84
85
            case 'preview':
86
87
                $document = $this->documentRepository->findByUid($piVars['qid']);
88
89
                if ($document) {
90
91
                    $metsXml = $this->buildMetsXml($document);
92
                    $this->response->setHeader('Content-Type', 'text/xml; charset=UTF-8');
93
                    return $metsXml;
94
95
                } else {
96
97
                    $this->response->setStatus(404);
98
                    return 'No such document';
99
100
                }
101
102
            case 'attachment':
103
104
                $qid = $piVars['qid'];
105
106
                $attachment = $piVars['attachment'];
107
108
                if (is_numeric($piVars['qid'])) {
109
110
                    // qid is local uid
111
                    $document = $this->documentRepository->findByUid($piVars['qid']);
112
113
                    $files = $document->getCurrentFileData();
114
115
                    foreach ($files['download'] as $id => $file) {
116
117
                        if ($file['id'] == $attachment) {
118
119
                            $path = $file['path'];
120
121
                            $contentType = $file['type'];
122
123
                            break;
124
125
                        }
126
                    }
127
128
                } else {
129
130
                    $path = rtrim('http://' . $fedoraHost, "/") . '/fedora/objects/' . $qid . '/datastreams/' . $attachment . '/content';
131
132
                }
133
134
                if (empty($path)) {
135
                    $this->response->setStatus(404);
136
                    return 'No file found';
137
                }
138
139
                break;
140
141
            case 'dataCite':
142
143
                $qid = $piVars['qid'];
144
                $source = explode(':', $qid);
145
                if($source[0] == 'qucosa') {
146
147
                    $path = rtrim('http://' . $fedoraHost,"/").'/fedora/objects/'.$piVars['qid'].'/methods/qucosa:SDef/getMETSDissemination?supplement=yes';
148
                    $metsXml = str_replace('&', '&amp;', file_get_contents($path));
149
                    $dataCiteXml = \EWW\Dpf\Helper\DataCiteXml::convertFromMetsXml($metsXml);
150
151
                } elseif($document = $this->documentRepository->findByUid($piVars['qid'])) {
152
153
                    $metsXml = str_replace('&', '&amp;', $this->buildMetsXml($document));
154
                    $dataCiteXml = \EWW\Dpf\Helper\DataCiteXml::convertFromMetsXml($metsXml);
155
156
                } else {
157
158
                    $this->response->setStatus(404);
159
                    return 'No such document';
160
161
                }
162
                $dom = new \DOMDocument('1.0', 'UTF-8');
163
                $dom->loadXML($dataCiteXml);
164
                $title = $dom->getElementsByTagName('title')[0];
165
166
                $this->response->setHeader('Content-Disposition', 'attachment; filename="' . self::sanitizeFilename($title->nodeValue) . '.DataCite.xml"');
167
                $this->response->setHeader('Content-Type', 'text/xml; charset=UTF-8');
168
                return $dataCiteXml;
169
170
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
171
172
            default:
173
174
                $this->response->setStatus(404);
175
176
                return 'No such action';
177
        }
178
179
        // get remote header and set it before passtrough
180
        $headers = get_headers($path);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $path does not seem to be defined for all execution paths leading up to this point.
Loading history...
181
182
        if (FALSE === $headers) {
0 ignored issues
show
introduced by
The condition FALSE === $headers can never be true.
Loading history...
183
            $this->response->setStatus(500);
184
            return 'Error while fetching headers';
185
        }
186
187
        $contentDispFlag = false;
188
        $contentTypeFlag = false;
189
190
        foreach ($headers as $value) {
191
192
            if (FALSE !== stripos($value, 'Content-Disposition')) {
193
                header($value);
194
                $contentDispFlag = true;
195
                continue;
196
            }
197
198
            if (FALSE !== stripos($value, 'Content-Type')) {
199
                header($value);
200
                $contentTypeFlag = true;
201
                continue;
202
            }
203
204
            if (FALSE !== stripos($value, 'Content-Length')) {
205
                header($value);
206
                continue;
207
            }
208
        }
209
210
        if (!$contentDispFlag) {
211
            header('Content-Disposition: attachment');
212
        }
213
214
        if (!$contentTypeFlag) {
215
            header('Content-Type: ' . $contentType);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $contentType does not seem to be defined for all execution paths leading up to this point.
Loading history...
216
        }
217
218
        if ($stream = fopen($path, 'r')) {
219
220
            // close active session if any
221
            session_write_close();
222
223
            // stop output buffering
224
            ob_end_clean();
225
226
            fpassthru($stream);
227
228
            fclose($stream);
229
230
            // Hard exit PHP script to avoid sending TYPO3 framework HTTP artifacts
231
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
232
233
        } else {
234
            $this->response->setStatus(500);
235
            return 'Error while opening stream';
236
        }
237
238
    }
239
240
    private static function sanitizeFilename($filename)
241
    {
242
        // remove anything which isn't a word, whitespace, number or any of the following caracters -_~,;[]().
243
        $filename = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $filename);
244
        // turn diacritical characters to ASCII
245
        setlocale(LC_ALL, 'en_US.utf8');
246
        $filename = iconv('utf-8', 'us-ascii//TRANSLIT', trim($filename));
247
        // replace whitespaces with underscore
248
        $filename = preg_replace('/\s+/', '_', $filename);
249
250
        return $filename;
251
    }
252
253
    private function buildMetsXml($document)
254
    {
255
256
        $exporter = new \EWW\Dpf\Services\MetsExporter();
257
        $fileData = $document->getCurrentFileData();
258
        $exporter->setFileData($fileData);
259
        $exporter->setMods($document->getXmlData());
260
        $exporter->setSlubInfo($document->getSlubInfoData());
261
262
        if (empty($document->getObjectIdentifier())) {
263
264
            $exporter->setObjId($document->getUid());
265
266
        } else {
267
268
            $exporter->setObjId($document->getObjectIdentifier());
269
270
        }
271
272
        $exporter->buildMets();
273
        $metsXml = $exporter->getMetsData();
274
275
        return $metsXml;
276
    }
277
278
    private function isForbidden($action) {
0 ignored issues
show
Unused Code introduced by
The method isForbidden() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
279
        return
280
            array_has_key('forbiddenActions', $this->settings)
0 ignored issues
show
Bug introduced by
The function array_has_key was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

280
            /** @scrutinizer ignore-call */ 
281
            array_has_key('forbiddenActions', $this->settings)
Loading history...
281
            && is_array($this->settings['forbiddenActions'])
282
            && in_array($action, $this->settings['forbiddenActions']);
283
    }
284
}
285
286