FileController::beforeAction()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 0
cts 6
cp 0
crap 6
rs 10
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\controllers;
13
14
use Craft;
15
use craft\helpers\FileHelper;
16
17
use craft\web\Controller;
18
use nystudio107\seomatic\helpers\UrlHelper;
19
use nystudio107\seomatic\Seomatic;
20
21
use yii\web\HttpException;
22
use yii\web\NotFoundHttpException;
23
use yii\web\Response;
24
use yii\web\ServerErrorHttpException;
25
26
/**
27
 * @author    nystudio107
28
 * @package   Seomatic
29
 * @since     3.0.0
30
 */
31
class FileController extends Controller
32
{
33
    // Properties
34
    // =========================================================================
35
36
    /**
37
     * @inheritdoc
38
     */
39
    protected $allowAnonymous = [
40
        'seo-file-link',
41
    ];
42
43
    // Public Methods
44
    // =========================================================================
45
46
    /**
47
     * @inheritDoc
48
     */
49
    public function beforeAction($action)
50
    {
51
        if (!Seomatic::$settings->enableSeoFileLinkEndpoint) {
52
            $this->allowAnonymous = false;
53
        }
54
55
        return parent::beforeAction($action);
56
    }
57
58
    /**
59
     * Allow setting the X-Robots-Tag and Link headers on static files as per:
60
     * https://moz.com/blog/how-to-advanced-relcanonical-http-headers
61
     *
62
     * @param        $url
63
     * @param string $robots
64
     * @param string $canonical
65
     * @param bool   $inline
66
     * @param string $fileName
67
     *
68
     * @return Response|\yii\console\Response
69
     * @throws HttpException
70
     * @throws NotFoundHttpException
71
     */
72
    public function actionSeoFileLink($url, $robots = '', $canonical = '', $inline = true, $fileName = '')
73
    {
74
        $url = base64_decode($url);
75
        $robots = base64_decode($robots);
76
        $canonical = base64_decode($canonical);
77
        $url = UrlHelper::absoluteUrlWithProtocol($url);
78
        $contents = file_get_contents($url);
79
        $response = Craft::$app->getResponse();
80
        if ($contents) {
81
            // Add the X-Robots-Tag header
82
            if (!empty($robots)) {
83
                $headerValue = $robots;
84
                $response->headers->add('X-Robots-Tag', $headerValue);
85
            }
86
            // Add the Link header
87
            if (!empty($canonical)) {
88
                $headerValue = '<' . $canonical . '>; rel="canonical"';
89
                $response->headers->add('Link', $headerValue);
90
            }
91
            // Ensure the file type is allowed
92
            // ref: https://craftcms.com/docs/3.x/config/config-settings.html#allowedfileextensions
93
            $allowedExtensions = Craft::$app->getConfig()->getGeneral()->allowedFileExtensions;
94
            if (($ext = pathinfo($fileName, PATHINFO_EXTENSION)) !== '') {
95
                $ext = strtolower($ext);
0 ignored issues
show
Bug introduced by
It seems like $ext can also be of type array; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

95
                $ext = strtolower(/** @scrutinizer ignore-type */ $ext);
Loading history...
96
            }
97
            if ($ext === '' || $ext === 'svg' || !in_array($ext, $allowedExtensions, true)) {
98
                throw new ServerErrorHttpException(Craft::t('seomatic', 'File format not allowed.'));
99
            }
100
            // Send the file as a stream, so it can exist anywhere
101
            $response->sendContentAsFile(
102
                $contents,
103
                $fileName,
104
                [
105
                    'inline' => $inline,
106
                    'mimeType' => FileHelper::getMimeTypeByExtension($fileName),
107
                ]
108
            );
109
        } else {
110
            throw new NotFoundHttpException(Craft::t('seomatic', 'File not found.'));
111
        }
112
113
        return $response;
114
    }
115
}
116