Passed
Push — develop ( 4239f4...1c065e )
by Andrew
04:44
created

DisqusService::getCommentsCount()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 38
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
c 3
b 0
f 0
nc 6
nop 1
dl 0
loc 38
rs 8.8657
1
<?php
2
/**
3
 * Disqus plugin for Craft CMS 3.x
4
 *
5
 * Integrates the Disqus commenting system into Craft 3 websites, including
6
 * Single Sign On (SSO) and custom login/logout URLs
7
 *
8
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
9
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\disqus\services;
13
14
use nystudio107\disqus\Disqus;
15
16
use Craft;
17
use craft\base\Component;
18
use craft\helpers\Template;
19
use craft\web\View;
20
21
use yii\base\Exception;
22
use yii\base\InvalidConfigException;
23
24
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
25
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
26
 * @package   Disqus
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
27
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
28
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
29
class DisqusService extends Component
30
{
31
    // Public Methods
32
    // =========================================================================
33
34
    /**
35
     * Output the Disqus Tag
36
     *
37
     * @param string $disqusIdentifier
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
38
     * @param string $disqusTitle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
39
     * @param string $disqusUrl
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
40
     * @param string $disqusCategoryId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
41
     * @param string $disqusLanguage
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
42
     *
43
     * @return string
44
     */
45
    public function outputEmbedTag(
46
        $disqusIdentifier = "",
47
        $disqusTitle = "",
48
        $disqusUrl = "",
49
        $disqusCategoryId = "",
50
        $disqusLanguage = ""
51
    ) {
52
        $settings = Disqus::$plugin->getSettings();
53
        $disqusShortname = $settings['disqusShortname'];
54
55
        $vars = [
56
            'disqusShortname'  => $disqusShortname,
57
            'disqusIdentifier' => $disqusIdentifier,
58
            'disqusTitle'      => $disqusTitle,
59
            'disqusUrl'        => $disqusUrl,
60
            'disqusCategoryId' => $disqusCategoryId,
61
            'disqusLanguage'   => $disqusLanguage,
62
        ];
63
        $vars = array_merge($vars, $this->getSSOVars());
64
        $result = $this->renderPluginTemplate('disqusEmbedTag', $vars);
65
66
        return $result;
67
    }
68
69
    /**
70
     * Return the number of comments for a particular thread
71
     *
72
     * @param string $disqusIdentifier
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
73
     *
74
     * @return int
75
     */
76
    public function getCommentsCount(
77
        $disqusIdentifier = ""
78
    ) {
79
80
        $settings = Disqus::$plugin->getSettings();
81
        if (Disqus::$craft31) {
82
            $settings['disqusPublicKey'] = Craft::parseEnv($settings['disqusPublicKey']);
83
            $settings['disqusSecretKey'] = Craft::parseEnv($settings['disqusSecretKey']);
84
        }
85
        if (!empty($settings['disqusPublicKey'])) {
86
            $disqusShortname = $settings['disqusShortname'];
87
            $apiKey = $settings["disqusPublicKey"];
88
89
            $url = "https://disqus.com/api/3.0/threads/details.json?api_key="
90
                .$apiKey
91
                ."&forum=".$disqusShortname
92
                ."&thread:ident="
93
                .$disqusIdentifier;
94
95
            $ch = curl_init();
96
            curl_setopt($ch, CURLOPT_URL, $url);
97
            curl_setopt($ch, CURLOPT_HEADER, 0);
98
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
99
            $return = curl_exec($ch);
100
            curl_close($ch);
101
102
            $json = json_decode($return, true);
0 ignored issues
show
Bug introduced by
It seems like $return can also be of type true; however, parameter $json of json_decode() 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

102
            $json = json_decode(/** @scrutinizer ignore-type */ $return, true);
Loading history...
103
            if ($json !== null && !empty($json["code"]) && $json["code"] == 0) {
104
                return $json["response"]["posts"];
105
            } else {
106
                Craft::error(Craft::t('disqus', print_r($json, true)), __METHOD__);
0 ignored issues
show
Bug introduced by
It seems like print_r($json, true) can also be of type true; however, parameter $message of yii\BaseYii::t() 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

106
                Craft::error(Craft::t('disqus', /** @scrutinizer ignore-type */ print_r($json, true)), __METHOD__);
Loading history...
107
108
                return 0;
109
            }
110
        } else {
111
            Craft::error(Craft::t('disqus', "Public API Key missing"), __METHOD__);
112
113
            return 0;
114
        }
115
    }
116
117
    // Protected Methods
118
    // =========================================================================
119
120
    /**
121
     * Return the SSO vars
122
     *
123
     * @return array
124
     */
125
    protected function getSSOVars(): array
126
    {
127
        $settings = Disqus::$plugin->getSettings();
128
        $vars = [
129
            'useSSO'         => false,
130
            'useCustomLogin' => false,
131
        ];
132
        if ($settings['useSSO']) {
133
            $data = [];
134
135
            // Set the data array
136
            $currentUser = Craft::$app->getUser()->getIdentity();
137
            if ($currentUser) {
0 ignored issues
show
introduced by
$currentUser is of type yii\web\IdentityInterface, thus it always evaluated to true.
Loading history...
138
                $data['id'] = $currentUser->id;
0 ignored issues
show
Bug introduced by
Accessing id on the interface yii\web\IdentityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
139
                if (Craft::$app->getConfig()->getGeneral()->useEmailAsUsername) {
140
                    $data['username'] = $currentUser->getFullName();
0 ignored issues
show
Bug introduced by
The method getFullName() does not exist on yii\web\IdentityInterface. It seems like you code against a sub-type of yii\web\IdentityInterface such as craft\elements\User. ( Ignorable by Annotation )

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

140
                    /** @scrutinizer ignore-call */ 
141
                    $data['username'] = $currentUser->getFullName();
Loading history...
141
                } else {
142
                    $data['username'] = $currentUser->username;
0 ignored issues
show
Bug introduced by
Accessing username on the interface yii\web\IdentityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
143
                }
144
                $data['email'] = $currentUser->email;
0 ignored issues
show
Bug introduced by
Accessing email on the interface yii\web\IdentityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
145
                try {
146
                    $data['avatar'] = $currentUser->getPhoto();
0 ignored issues
show
Bug introduced by
The method getPhoto() does not exist on yii\web\IdentityInterface. It seems like you code against a sub-type of yii\web\IdentityInterface such as craft\elements\User. ( Ignorable by Annotation )

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

146
                    /** @scrutinizer ignore-call */ 
147
                    $data['avatar'] = $currentUser->getPhoto();
Loading history...
147
                } catch (InvalidConfigException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
148
                }
149
            }
150
151
            // Encode the data array and generate the hMac
152
            $message = base64_encode(json_encode($data));
153
            $timestamp = time();
154
            $hMac = $this->disqusHmacSha1(
155
                $message
156
                .' '
157
                .$timestamp,
158
                $settings['disqusSecretKey']
159
            );
160
161
            // Set the vars for the template
162
            $vars = array_merge($vars, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
163
                'useSSO'          => true,
164
                'message'         => $message,
165
                'hmac'            => $hMac,
166
                'timestamp'       => $timestamp,
167
                'disqusPublicKey' => $settings['disqusPublicKey'],
168
            ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
169
170
            // Set the vars for the custom login
171
            if ($settings['customLogin']) {
172
                $vars = array_merge($vars, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
173
                    'useCustomLogin' => true,
174
                    'loginName'      => $settings['loginName'],
175
                    'loginButton'    => $settings['loginButton'],
176
                    'loginIcon'      => $settings['loginIcon'],
177
                    'loginUrl'       => $settings['loginUrl'],
178
                    'loginLogoutUrl' => $settings['loginLogoutUrl'],
179
                    'loginWidth'     => $settings['loginWidth'],
180
                    'loginHeight'    => $settings['loginHeight'],
181
                ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
182
            }
183
        }
184
185
        return $vars;
186
    }
187
188
    /**
189
     * Render a plugin template
190
     *
191
     * @param $templatePath
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
192
     * @param $vars
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
193
     *
194
     * @return string
195
     */
196
    protected function renderPluginTemplate($templatePath, $vars)
197
    {
198
        // Stash the old template mode, and set it Control Panel template mode
199
        $oldMode = Craft::$app->view->getTemplateMode();
200
        try {
201
            Craft::$app->view->setTemplateMode(View::TEMPLATE_MODE_CP);
202
        } catch (Exception $e) {
203
            Craft::error($e->getMessage(), __METHOD__);
204
        }
205
206
        // Render the template with our vars passed in
207
        try {
208
            $htmlText = Craft::$app->view->renderTemplate('disqus/'.$templatePath, $vars);
209
        } catch (\Exception $e) {
210
            $htmlText = 'Error rendering template '.$templatePath.' -> '.$e->getMessage();
211
            Craft::error(Craft::t('disqus', $htmlText), __METHOD__);
212
        }
213
214
        // Restore the old template mode
215
        try {
216
            Craft::$app->view->setTemplateMode($oldMode);
217
        } catch (Exception $e) {
218
            Craft::error($e->getMessage(), __METHOD__);
219
        }
220
221
        return Template::raw($htmlText);
222
    }
223
224
    /**
225
     * HMAC->SHA1
226
     * From:
227
     * https://github.com/disqus/DISQUS-API-Recipes/blob/master/sso/php/sso.php
228
     *
229
     * @param $data
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
230
     * @param $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
231
     *
232
     * @return string
233
     */
234
    protected function disqusHmacSha1($data, $key)
235
    {
236
        $blockSize = 64;
237
        $hashFunc = 'sha1';
238
        if (strlen($key) > $blockSize) {
239
            $key = pack('H*', $hashFunc($key));
240
        }
241
        $key = str_pad($key, $blockSize, chr(0x00));
242
        $iPad = str_repeat(chr(0x36), $blockSize);
243
        $oPad = str_repeat(chr(0x5c), $blockSize);
244
        $hMac = pack(
245
            'H*',
246
            $hashFunc(
247
                ($key ^ $oPad).pack(
248
                    'H*',
249
                    $hashFunc(
250
                        ($key ^ $iPad).$data
251
                    )
252
                )
253
            )
254
        );
255
256
        return bin2hex($hMac);
257
    }
258
}
259