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
![]() |
|||||||
9 | * @copyright Copyright (c) 2017 nystudio107 |
||||||
0 ignored issues
–
show
|
|||||||
10 | */ |
||||||
0 ignored issues
–
show
|
|||||||
11 | |||||||
12 | namespace nystudio107\disqus\services; |
||||||
13 | |||||||
14 | use Craft; |
||||||
15 | use craft\base\Component; |
||||||
16 | use craft\helpers\Html; |
||||||
17 | use craft\helpers\Template; |
||||||
18 | use craft\web\User; |
||||||
19 | use craft\web\View; |
||||||
20 | use nystudio107\disqus\Disqus; |
||||||
21 | use nystudio107\disqus\models\Settings; |
||||||
22 | use Twig\Markup; |
||||||
23 | use yii\base\Exception; |
||||||
24 | use yii\base\InvalidConfigException; |
||||||
25 | |||||||
26 | /** |
||||||
0 ignored issues
–
show
|
|||||||
27 | * @author nystudio107 |
||||||
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
![]() |
|||||||
28 | * @package Disqus |
||||||
0 ignored issues
–
show
|
|||||||
29 | * @since 1.0.0 |
||||||
0 ignored issues
–
show
|
|||||||
30 | */ |
||||||
0 ignored issues
–
show
|
|||||||
31 | class DisqusService extends Component |
||||||
32 | { |
||||||
33 | // Public Methods |
||||||
34 | // ========================================================================= |
||||||
35 | |||||||
36 | /** |
||||||
37 | * Output the Disqus Tag |
||||||
38 | * |
||||||
39 | * @param string $disqusIdentifier |
||||||
0 ignored issues
–
show
|
|||||||
40 | * @param string $disqusTitle |
||||||
0 ignored issues
–
show
|
|||||||
41 | * @param string $disqusUrl |
||||||
0 ignored issues
–
show
|
|||||||
42 | * @param string $disqusCategoryId |
||||||
0 ignored issues
–
show
|
|||||||
43 | * @param string $disqusLanguage |
||||||
0 ignored issues
–
show
|
|||||||
44 | * @param array $scriptAttributes |
||||||
0 ignored issues
–
show
|
|||||||
45 | * |
||||||
46 | * @return Markup |
||||||
47 | */ |
||||||
48 | public function outputEmbedTag( |
||||||
49 | string $disqusIdentifier = "", |
||||||
50 | string $disqusTitle = "", |
||||||
51 | string $disqusUrl = "", |
||||||
52 | string $disqusCategoryId = "", |
||||||
53 | string $disqusLanguage = "", |
||||||
54 | array $scriptAttributes = [], |
||||||
55 | ): Markup { |
||||||
56 | /** @var Settings $settings */ |
||||||
0 ignored issues
–
show
|
|||||||
57 | $settings = Disqus::$plugin->getSettings(); |
||||||
0 ignored issues
–
show
The method
getSettings() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
58 | $disqusShortname = $settings->getDisqusShortName(); |
||||||
59 | |||||||
60 | $vars = [ |
||||||
61 | 'disqusShortname' => $disqusShortname, |
||||||
62 | 'disqusIdentifier' => $disqusIdentifier, |
||||||
63 | 'disqusTitle' => $disqusTitle, |
||||||
64 | 'disqusUrl' => $disqusUrl, |
||||||
65 | 'disqusCategoryId' => $disqusCategoryId, |
||||||
66 | 'disqusLanguage' => $disqusLanguage, |
||||||
67 | 'scriptAttributes' => Html::renderTagAttributes($scriptAttributes), |
||||||
68 | ]; |
||||||
69 | $vars = array_merge($vars, $this->getSSOVars()); |
||||||
70 | $templateName = 'disqusEmbedTag'; |
||||||
71 | if ($settings->lazyLoadDisqus) { |
||||||
72 | $templateName = 'disqusEmbedTagLazy'; |
||||||
73 | } |
||||||
74 | |||||||
75 | return $this->renderPluginTemplate($templateName, $vars); |
||||||
76 | } |
||||||
77 | |||||||
78 | /** |
||||||
79 | * Return the number of comments for a particular thread |
||||||
80 | * |
||||||
81 | * @param string $disqusIdentifier |
||||||
0 ignored issues
–
show
|
|||||||
82 | * |
||||||
83 | * @return int |
||||||
0 ignored issues
–
show
|
|||||||
84 | * @noinspection PhpComposerExtensionStubsInspection |
||||||
85 | */ |
||||||
86 | public function getCommentsCount( |
||||||
87 | string $disqusIdentifier = "", |
||||||
88 | ): int { |
||||||
89 | /** @var Settings $settings */ |
||||||
0 ignored issues
–
show
|
|||||||
90 | $settings = Disqus::$plugin->getSettings(); |
||||||
91 | if (!empty($settings->getDisqusPublicKey())) { |
||||||
92 | $disqusShortname = $settings->getDisqusShortname(); |
||||||
93 | $apiKey = $settings->getDisqusPublicKey(); |
||||||
94 | |||||||
95 | $url = "https://disqus.com/api/3.0/threads/details.json?api_key=" |
||||||
96 | . $apiKey |
||||||
97 | . "&forum=" . $disqusShortname |
||||||
98 | . "&thread:ident=" |
||||||
99 | . $disqusIdentifier; |
||||||
100 | |||||||
101 | $ch = curl_init(); |
||||||
102 | curl_setopt($ch, CURLOPT_URL, $url); |
||||||
103 | curl_setopt($ch, CURLOPT_HEADER, 0); |
||||||
104 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||||||
105 | $return = curl_exec($ch); |
||||||
106 | curl_close($ch); |
||||||
107 | |||||||
108 | $json = json_decode($return, true); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
109 | if ($json !== null && !empty($json["code"]) && $json["code"] == 0) { |
||||||
110 | return $json["response"]["posts"]; |
||||||
111 | } else { |
||||||
112 | Craft::error(Craft::t('disqus', print_r($json, true)), __METHOD__); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
113 | |||||||
114 | return 0; |
||||||
115 | } |
||||||
116 | } else { |
||||||
117 | Craft::error(Craft::t('disqus', "Public API Key missing"), __METHOD__); |
||||||
118 | |||||||
119 | return 0; |
||||||
120 | } |
||||||
121 | } |
||||||
122 | |||||||
123 | // Protected Methods |
||||||
124 | // ========================================================================= |
||||||
125 | |||||||
126 | /** |
||||||
127 | * Return the SSO vars |
||||||
128 | * |
||||||
129 | * @return array |
||||||
130 | */ |
||||||
131 | protected function getSSOVars(): array |
||||||
132 | { |
||||||
133 | /** @var Settings $settings */ |
||||||
0 ignored issues
–
show
|
|||||||
134 | $settings = Disqus::$plugin->getSettings(); |
||||||
135 | $vars = [ |
||||||
136 | 'useSSO' => false, |
||||||
137 | 'useCustomLogin' => false, |
||||||
138 | ]; |
||||||
139 | if ($settings->getUseSSO()) { |
||||||
140 | $data = []; |
||||||
141 | |||||||
142 | // Set the data array |
||||||
143 | /** @var User $user */ |
||||||
0 ignored issues
–
show
|
|||||||
144 | $user = Craft::$app->getUser(); |
||||||
145 | $currentUser = $user->getIdentity(); |
||||||
146 | if ($currentUser) { |
||||||
147 | $data['id'] = $currentUser->id; |
||||||
148 | if (Craft::$app->getConfig()->getGeneral()->useEmailAsUsername) { |
||||||
149 | $data['username'] = $currentUser->getFullName(); |
||||||
0 ignored issues
–
show
The function
craft\elements\User::getFullName() has been deprecated: in 4.0.0. [[fullName]] should be used instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
150 | } else { |
||||||
151 | $data['username'] = $currentUser->username; |
||||||
152 | } |
||||||
153 | $data['email'] = $currentUser->email; |
||||||
154 | try { |
||||||
155 | $data['avatar'] = $currentUser->getPhoto()->getUrl(); |
||||||
156 | } catch (InvalidConfigException $e) { |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
157 | } |
||||||
158 | } |
||||||
159 | |||||||
160 | // Encode the data array and generate the hMac |
||||||
161 | $message = base64_encode(json_encode($data)); |
||||||
162 | $timestamp = time(); |
||||||
163 | $hMac = $this->disqusHmacSha1( |
||||||
164 | $message |
||||||
165 | . ' ' |
||||||
166 | . $timestamp, |
||||||
167 | $settings->getDisqusSecretKey() |
||||||
168 | ); |
||||||
169 | |||||||
170 | // Set the vars for the template |
||||||
171 | $vars = array_merge($vars, [ |
||||||
0 ignored issues
–
show
|
|||||||
172 | 'useSSO' => true, |
||||||
173 | 'message' => $message, |
||||||
174 | 'hmac' => $hMac, |
||||||
175 | 'timestamp' => $timestamp, |
||||||
176 | 'disqusPublicKey' => $settings->getDisqusPublicKey(), |
||||||
177 | ]); |
||||||
0 ignored issues
–
show
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.
![]() |
|||||||
178 | |||||||
179 | // Set the vars for the custom login |
||||||
180 | if ($settings->getCustomLogin()) { |
||||||
181 | $vars = array_merge($vars, [ |
||||||
0 ignored issues
–
show
|
|||||||
182 | 'useCustomLogin' => true, |
||||||
183 | 'loginName' => $settings->getLoginName(), |
||||||
184 | 'loginButton' => $settings->getLoginButton(), |
||||||
185 | 'loginIcon' => $settings->getLoginIcon(), |
||||||
186 | 'loginUrl' => $settings->getLoginUrl(), |
||||||
187 | 'loginLogoutUrl' => $settings->getLoginLogoutUrl(), |
||||||
188 | 'loginWidth' => $settings->getLoginWidth(), |
||||||
189 | 'loginHeight' => $settings->getLoginHeight(), |
||||||
190 | ]); |
||||||
0 ignored issues
–
show
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.
![]() |
|||||||
191 | } |
||||||
192 | } |
||||||
193 | |||||||
194 | return $vars; |
||||||
195 | } |
||||||
196 | |||||||
197 | /** |
||||||
198 | * Render a plugin template |
||||||
199 | * |
||||||
200 | * @param $templatePath |
||||||
0 ignored issues
–
show
|
|||||||
201 | * @param $vars |
||||||
0 ignored issues
–
show
|
|||||||
202 | * |
||||||
203 | * @return Markup |
||||||
204 | */ |
||||||
205 | protected function renderPluginTemplate($templatePath, $vars): Markup |
||||||
206 | { |
||||||
207 | // Stash the old template mode, and set it Control Panel template mode |
||||||
208 | $oldMode = Craft::$app->view->getTemplateMode(); |
||||||
209 | try { |
||||||
210 | Craft::$app->view->setTemplateMode(View::TEMPLATE_MODE_CP); |
||||||
211 | } catch (Exception $e) { |
||||||
212 | Craft::error($e->getMessage(), __METHOD__); |
||||||
213 | } |
||||||
214 | |||||||
215 | // Render the template with our vars passed in |
||||||
216 | try { |
||||||
217 | $htmlText = Craft::$app->view->renderTemplate('disqus/' . $templatePath, $vars); |
||||||
218 | } catch (\Exception $e) { |
||||||
219 | $htmlText = 'Error rendering template ' . $templatePath . ' -> ' . $e->getMessage(); |
||||||
220 | Craft::error(Craft::t('disqus', $htmlText), __METHOD__); |
||||||
221 | } |
||||||
222 | |||||||
223 | // Restore the old template mode |
||||||
224 | try { |
||||||
225 | Craft::$app->view->setTemplateMode($oldMode); |
||||||
226 | } catch (Exception $e) { |
||||||
227 | Craft::error($e->getMessage(), __METHOD__); |
||||||
228 | } |
||||||
229 | |||||||
230 | return Template::raw($htmlText); |
||||||
231 | } |
||||||
232 | |||||||
233 | /** |
||||||
234 | * HMAC->SHA1 |
||||||
235 | * From: |
||||||
236 | * https://github.com/disqus/DISQUS-API-Recipes/blob/master/sso/php/sso.php |
||||||
237 | * |
||||||
238 | * @param $data |
||||||
0 ignored issues
–
show
|
|||||||
239 | * @param $key |
||||||
0 ignored issues
–
show
|
|||||||
240 | * |
||||||
241 | * @return string |
||||||
242 | */ |
||||||
243 | protected function disqusHmacSha1($data, $key): string |
||||||
244 | { |
||||||
245 | $blockSize = 64; |
||||||
246 | $hashFunc = 'sha1'; |
||||||
247 | if (strlen($key) > $blockSize) { |
||||||
248 | $key = pack('H*', $hashFunc($key)); |
||||||
249 | } |
||||||
250 | $key = str_pad($key, $blockSize, chr(0x00)); |
||||||
251 | $iPad = str_repeat(chr(0x36), $blockSize); |
||||||
252 | $oPad = str_repeat(chr(0x5c), $blockSize); |
||||||
253 | $hMac = pack( |
||||||
254 | 'H*', |
||||||
255 | $hashFunc( |
||||||
256 | ($key ^ $oPad) . pack( |
||||||
257 | 'H*', |
||||||
258 | $hashFunc( |
||||||
259 | ($key ^ $iPad) . $data |
||||||
260 | ) |
||||||
261 | ) |
||||||
262 | ) |
||||||
263 | ); |
||||||
264 | |||||||
265 | return bin2hex($hMac); |
||||||
266 | } |
||||||
267 | } |
||||||
268 |