· 7 years ago · Apr 15, 2018, 02:48 PM
1<?php
2
3namespace frontend\controllers;
4
5use common\components\Y;
6use common\models\Auth;
7use common\models\Subscriber;
8use common\models\User;
9use Sunra\PhpSimple\HtmlDomParser;
10use Yii;
11use yii\authclient\ClientInterface;
12use yii\base\Exception;
13use yii\base\InvalidParamException;
14use yii\helpers\ArrayHelper;
15use yii\helpers\Html;
16use yii\helpers\Url;
17use yii\httpclient\Client;
18use yii\web\BadRequestHttpException;
19use yii\web\Controller;
20use yii\filters\VerbFilter;
21use yii\filters\AccessControl;
22use common\models\LoginForm;
23use frontend\models\PasswordResetRequestForm;
24use frontend\models\ResetPasswordForm;
25use common\models\SignupForm;
26use frontend\models\ContactForm;
27
28/**
29 * Site controller
30 */
31class SiteController extends Controller
32{
33 const EMPTY_SOCIAL_EMAIL_MESSAGE = 'Email not found, please enter your email, username and password and click signup, that would link the future profile with the social network';
34 const SIGNUP_EMAIL_MESSAGE_FOUND = 'Please enter your username and password and click signup, that would link the future profile with the social network';
35
36 public $enableCsrfValidation = false;
37
38 /**
39 * @inheritdoc
40 */
41 public function behaviors()
42 {
43 return [
44 'access' => [
45 'class' => AccessControl::className(),
46 'only' => ['logout', 'signup', 'auth', 'test'],
47 'rules' => [
48 [
49 'actions' => ['auth'],
50 #'allow' => false,
51 'allow' => true,
52 #'roles' => ['@'],
53 ],
54 [
55 'actions' => ['signup'],
56 #'allow' => false,
57 'allow' => true,
58 #'roles' => ['@'],
59 ],
60 [
61 'actions' => ['logout'],
62 'allow' => true,
63 'roles' => ['@'],
64 ],
65 [
66 'actions' => ['test'],
67 'allow' => true,
68 #'roles' => ['@'],
69 ],
70 ],
71 ],
72 /*'verbs' => [
73 'class' => VerbFilter::className(),
74 'actions' => [
75 'logout' => ['post'],
76 ],
77 ],*/
78 ];
79 }
80
81 public function actionTest()
82 {
83 if ($dcLinkList = $this->getDcLinkList()) {
84 $cnt=1;
85 foreach ($dcLinkList as $dcLink) {
86 #if ($cnt == 4) {
87 if ($cnt == 12) {
88 $dcData = $this->getDcData($dcLink);
89
90 Y::dump($dcData, true);
91 }
92
93 $cnt++;
94 }
95 }
96
97 Y::dump($dcLinkList, true);
98 }
99
100 protected function getDcData($link)
101 {
102 $client = new Client();
103 $rawContent = $client->createRequest()
104 ->setUrl($link)
105 ->setMethod('get')
106 ->addHeaders([
107 'Accept-Language' => 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
108 'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
109 ])
110 #->setFormat(Client::FORMAT_JSON)
111 ->send()
112 ->getContent();
113
114 $dom = HtmlDomParser::str_get_html(trim($rawContent));
115
116 /*$countryName = null;
117 if ($pageContentContentTitle = $dom->find('.pagecontentContent-title', 0)) {
118 if ($countryNameBlock = $pageContentContentTitle->find('h1', 0)) {
119 $countryNameBlock = $countryNameBlock->innertext();
120 $countryNameBlockExp = explode('/', $countryNameBlock);
121 if ($countryNameBlockExp && count($countryNameBlockExp) == 3) {
122 $countryName = trim($countryNameBlockExp[1]);
123 }
124 }
125 }*/
126
127 $dcName = null;
128 $dcLink = null;
129
130 if ($clearfixNode = $dom->find('.clearfix', 2)) {
131 if ($divs = $clearfixNode->find('div')) {
132 foreach ($divs as $div) {
133 $dcLink = null;
134 $style = ArrayHelper::getValue($div, 'attr.style', false);
135 if ($style && $style == 'width: 100%; float: left;') {
136 if ($imgs = $div->find('img')) {
137 foreach ($imgs as $img) {
138 $imgTitle = ArrayHelper::getValue($img, 'attr.title', false);
139 if ($imgTitle && $imgTitle == 'Centro de buceo') {
140 if ($div = $div->find('div', 2)) {
141 if ($strong = $div->find('strong', 0)) {
142 $dcName = html_entity_decode($strong->text());
143 if (strripos($strong->innertext(), 'href')) {
144 if ($dcAHrefNode = $strong->find('a', 0)) {
145 $dcLink = ArrayHelper::getValue($dcAHrefNode, 'attr.href', null);
146 }
147 }
148
149 Y::dump($strong->outertext(), false);
150 }
151 #$expBr = explode('<br>', $div->innertext());
152 Y::dump($div->innertext(), false);
153 }
154
155 #Y::dump($div->innertext(), false);
156 }
157 }
158 }
159 }
160 }
161 }
162 }
163
164 Y::dump('test', true);
165 }
166
167 protected function getDcLinkList()
168 {
169 $client = new Client(['baseUrl' => 'http://acuc.es']);
170 $rawContent = $client->createRequest()
171 ->setUrl('/en/diving-centers/')
172 ->setMethod('get')
173 ->addHeaders([
174 'Accept-Language' => 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
175 'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
176 ])
177 #->setFormat(Client::FORMAT_JSON)
178 ->send()
179 ->getContent();
180
181 $dom = HtmlDomParser::str_get_html(trim($rawContent));
182 $dcLinkList = [];
183 if ($aDc = $dom->find('#aq-block-11370-12', 0)->find('a')) {
184 foreach ($aDc as $child) {
185 if ($href = ArrayHelper::getValue($child, 'attr.href' , false)) {
186 $dcLinkList[] = $href;
187 }
188 }
189 }
190
191 #Y::dump($dcLinkList, true);
192
193 return $dcLinkList;
194 }
195
196 /**
197 * @inheritdoc
198 */
199 public function actions()
200 {
201 return [
202 'error' => [
203 'class' => 'yii\web\ErrorAction',
204 ],
205 'captcha' => [
206 'class' => 'yii\captcha\CaptchaAction',
207 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
208 ],
209 'auth' => [
210 'class' => 'yii\authclient\AuthAction',
211 'successCallback' => [$this, 'onAuthSuccess'],
212 ],
213 ];
214 }
215
216 public function onAuthSuccess(ClientInterface $client)
217 {
218 Yii::$app->getUser()->setReturnUrl(Url::to(['/site/signup']));
219
220 $attributes = $client->getUserAttributes();
221 $source = $client->getId();
222 $sourceTitle = $client->getTitle();
223
224 #Y::dump($id, false);
225 #Y::dump($attributes, true);
226
227 $this->prepareAuthSuccess($attributes, $source, $sourceTitle);
228 }
229
230 /**
231 * @param $attributes
232 * @param $source
233 * @param $sourceTitle
234 */
235 protected function prepareAuthSuccess($attributes, $source, $sourceTitle)
236 {
237 $email = ArrayHelper::getValue($attributes, 'User.email');
238 $sourceId = ArrayHelper::getValue($attributes, 'AuthData.source_id');
239
240 /* @var Auth $auth */
241 $auth = Auth::find()->where([
242 'source' => $source,
243 'source_id' => $sourceId,
244 ])->one();
245
246 if (Yii::$app->user->isGuest) {
247 if ($auth) { // login
248 /* @var User $user */
249 $user = $auth->user;
250 Yii::$app->getUser()->setReturnUrl(Url::to(['/user']));
251 Yii::$app->user->login($user, Yii::$app->params['user.passwordResetTokenExpire']);
252 } else { // signup
253
254 if (!is_null($email)) {
255 if ($user = User::findOne(['email' => $email])) {
256 $transaction = User::getDb()->beginTransaction();
257
258 $auth = new Auth([
259 'user_id' => $user->id,
260 'source' => $source,
261 'source_id' => (string) $sourceId,
262 ]);
263 if ($auth->save()) {
264 $transaction->commit();
265 Yii::$app->user->login($user, Yii::$app->params['user.passwordResetTokenExpire']);
266 } else {
267 Yii::$app->getSession()->setFlash('error', 'Unable to save, errors: ' . json_encode($auth->getErrors()));
268 }
269 } else {
270 $this->setSessionSocialDetails($attributes);
271 Yii::$app->getSession()->setFlash('emailError', self::SIGNUP_EMAIL_MESSAGE_FOUND);
272 }
273 } else {
274 $this->setSessionSocialDetails($attributes);
275 Yii::$app->getSession()->setFlash('emailError', self::EMPTY_SOCIAL_EMAIL_MESSAGE);
276 }
277 }
278 } else { // user already logged in
279 if (!$auth) { // add auth provider
280 #Y::dump($attributes, true);
281 $auth = new Auth([
282 'user_id' => Yii::$app->user->id,
283 'source' => $source,
284 'source_id' => (string) $sourceId,
285 ]);
286 if ($auth->save()) {
287 Yii::$app->getSession()->setFlash('success', [
288 Yii::t('app', 'Linked {client} account.', [
289 'client' => $sourceTitle
290 ]),
291 ]);
292 } else {
293 Yii::$app->getSession()->setFlash('error', [
294 Yii::t('app', 'Unable to link {client} account: {errors}', [
295 'client' => $sourceTitle,
296 'errors' => json_encode($auth->getErrors()),
297 ]),
298 ]);
299 }
300 } else { // there's existing auth
301 Yii::$app->getSession()->setFlash('error', [
302 Yii::t('app',
303 'Unable to link {client} account. There is another user using it.',
304 ['client' => $sourceTitle]),
305 ]);
306 }
307 }
308 }
309
310 /**
311 * @param array $attributes
312 */
313 protected function setSessionSocialDetails($attributes)
314 {
315 Y::app()->getSession()->set(
316 'socialDetail',
317 ArrayHelper::merge(
318 ArrayHelper::getValue($attributes, 'User'),
319 ArrayHelper::getValue($attributes, 'AuthData')
320 )
321 );
322 }
323
324 /**
325 * @return \yii\web\Response
326 */
327 public function actionTelegramAuth()
328 {
329 Yii::$app->getUser()->setReturnUrl(Url::to(['/site/signup']));
330
331 $attributes = $this->validateTelegramAuthHash(Y::request()->get());
332
333 $source = 'telegram';
334 $sourceTitle = 'Telegram';
335 $return_attributes = [
336 'User' => [
337 'email' => null,
338 'username' => ArrayHelper::getValue($attributes, 'username', null),
339 'photo' => ArrayHelper::getValue($attributes, 'photo_url', null),
340 'sex' => null
341 ],
342 'AuthData' => [
343 'source' => $source,
344 'source_id' => ArrayHelper::getValue($attributes, 'id'),
345 ],
346 ];
347
348 #Y::dump($return_attributes, true);
349
350 $this->prepareAuthSuccess($return_attributes, $source, $sourceTitle);
351
352 return $this->redirect(Yii::$app->getUser()->getReturnUrl());
353 }
354
355 /**
356 * @param $authData
357 * @return mixed
358 * @throws Exception
359 */
360 protected function validateTelegramAuthHash($authData)
361 {
362 $checkHash = $authData['hash'];
363 unset($authData['hash']);
364 $dataCheckArr = [];
365 foreach ($authData as $key => $value) {
366 $dataCheckArr[] = $key . '=' . $value;
367 }
368 sort($dataCheckArr);
369 $dataCheckString = implode("\n", $dataCheckArr);
370 $secretKey = hash('sha256', Yii::$app->params['telegramBotTokenAuth'], true);
371 $hash = hash_hmac('sha256', $dataCheckString, $secretKey);
372
373 if (strcmp($hash, $checkHash) !== 0) {
374 throw new Exception('Data is NOT from Telegram');
375 }
376
377 if ((time() - $authData['auth_date']) > 86400) {
378 throw new Exception('Data is outdated');
379 }
380
381 return $authData;
382 }
383
384 /**
385 * Displays homepage.
386 *
387 * @return mixed
388 */
389 public function actionIndex()
390 {
391 return $this->render('index');
392 }
393
394 /**
395 * Signs user up.
396 *
397 * @return mixed
398 */
399 public function actionSignup()
400 {
401 if (!Yii::$app->user->isGuest) {
402 #return $this->goHome();
403 return $this->redirect('/user');
404 }
405
406 $this->setSiteLayout();
407
408 $socialDetail = [];
409 if (Y::app()->getSession()->has('socialDetail')) {
410 $socialDetail = Y::app()->getSession()->get('socialDetail');
411 }
412
413 $model = new SignupForm();
414 if ($model->load(Yii::$app->request->post()) && $model->validate()) {
415 if ($user = $model->signup()) {
416 #if (Yii::$app->getUser()->login($user)) {
417
418 if (Y::app()->getSession()->has('socialDetail')) {
419 Y::app()->getSession()->remove('socialDetail');
420 }
421
422 SignupForm::sentEmailConfirm($user);
423 Y::app()->getSession()->setFlash('needConfirm', 'Check your email to confirm the registration.');
424 return $this->redirect('/signup');
425
426 #return $this->goHome();
427 #return $this->redirect('/user');
428 #}
429 }
430 }
431
432 return $this->render('authenticate_signup', [
433 'model' => $model,
434 'email' => ArrayHelper::getValue($socialDetail, 'email', false),
435 'source' => ArrayHelper::getValue($socialDetail, 'source', false),
436 'source_id' => ArrayHelper::getValue($socialDetail, 'source_id', false),
437 'username' => ArrayHelper::getValue($socialDetail, 'username', false),
438 'photo' => ArrayHelper::getValue($socialDetail, 'photo', false),
439 ]);
440 }
441
442 public function actionSignupConfirm($token)
443 {
444 try{
445 if (empty($token)) {
446 throw new \DomainException('Empty confirm token.');
447 }
448
449 $user = User::findOne(['email_confirm_token' => $token]);
450 if (!$user) {
451 throw new \DomainException('User is not found.');
452 }
453
454 $user->email_confirm_token = null;
455 $user->status = User::STATUS_ACTIVE;
456 if (!$user->save()) {
457 throw new \RuntimeException('Saving error.');
458 }
459
460 if (!Yii::$app->getUser()->login($user)){
461 throw new \RuntimeException('Error authentication.');
462 }
463
464 Yii::$app->session->setFlash('success', 'You have successfully confirmed your registration.');
465 } catch (\Exception $e){
466 Yii::$app->errorHandler->logException($e);
467 Yii::$app->session->setFlash('error', $e->getMessage());
468 return $this->redirect('/signup');
469 }
470
471 return $this->redirect('/user');
472 }
473
474 /**
475 * @param $email
476 * @return string
477 */
478 public function actionSubscribe($email)
479 {
480 $subscriber = new Subscriber();
481 $subscriber->email = strtolower($email);
482 $subscriber->save();
483
484 return '';
485 }
486
487 /**
488 * Logs in a user.
489 *
490 * @return mixed
491 */
492 public function actionLogin()
493 {
494 if (!Yii::$app->user->isGuest) {
495 #return $this->goHome();
496 return $this->redirect('/user');
497 }
498
499 $this->setSiteLayout();
500
501 $model = new LoginForm();
502 if (!Yii::$app->request->isPost) {
503 return $this->render('authenticate_login', [
504 'model' => $model,
505 ]);
506 }
507
508 if ($model->load(Yii::$app->request->post())) {
509 try{
510 if ($model->login()) {
511 if (Yii::$app->getUser()->getReturnUrl(null) == '/') {
512 return $this->redirect('/user');
513 }
514 return $this->goBack();
515 } else {
516 Yii::$app->getSession()->setFlash('error', 'Incorrect email or password.');
517 }
518 } catch (\DomainException $e){
519 Yii::$app->session->setFlash('error', $e->getMessage());
520 return $this->redirect('/login');
521 }
522 }
523
524 return $this->render('authenticate_login', [
525 'model' => $model,
526 ]);
527 }
528
529 /**
530 * Logs out the current user.
531 *
532 * @return mixed
533 */
534 public function actionLogout()
535 {
536 Yii::$app->user->logout();
537
538 return $this->redirect('login');
539
540 #return $this->goHome();
541 }
542
543// /**
544// * Displays contact page.
545// *
546// * @return mixed
547// */
548// public function actionContact()
549// {
550// $model = new ContactForm();
551// if ($model->load(Yii::$app->request->post()) && $model->validate()) {
552// if ($model->sendEmail(Yii::$app->params['adminEmail'])) {
553// Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.');
554// } else {
555// Yii::$app->session->setFlash('error', 'There was an error sending your message.');
556// }
557//
558// return $this->refresh();
559// } else {
560// return $this->render('contact', [
561// 'model' => $model,
562// ]);
563// }
564// }
565//
566// /**
567// * Displays about page.
568// *
569// * @return mixed
570// */
571// public function actionAbout()
572// {
573// return $this->render('about');
574// }
575
576 /**
577 * Requests password reset.
578 *
579 * @return mixed
580 */
581 public function actionRequestPasswordReset()
582 {
583 $this->setSiteLayout();
584
585 $model = new PasswordResetRequestForm();
586 if (Y::request()->isPost) {
587 if ($model->load(Yii::$app->request->post()) && $model->validate()) {
588 if ($model->sendEmail()) {
589 Yii::$app->session->setFlash('success', 'Check your email for further instructions.');
590
591 return $this->redirect('request-password-reset');
592 #return $this->goHome();
593 } else {
594 Yii::$app->session->setFlash('errorReset', 'Sorry, we are unable to reset password for the provided email address.');
595 }
596 } else {
597 Yii::$app->session->setFlash('errorReset', Html::errorSummary($model));
598 }
599 }
600
601 return $this->render('requestPasswordReset', [
602 'model' => $model,
603 ]);
604 }
605
606 /**
607 * Resets password.
608 *
609 * @param string $token
610 * @return mixed
611 * @throws BadRequestHttpException
612 */
613 public function actionChangePassword($token)
614 {
615 #$this->layout = false;
616 $this->setSiteLayout();
617
618 try {
619 $model = new ResetPasswordForm($token);
620 } catch (InvalidParamException $e) {
621 throw new BadRequestHttpException($e->getMessage());
622 }
623
624 if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {
625 Yii::$app->session->setFlash('success', 'New password saved.');
626
627 return $this->goHome();
628 }
629
630 return $this->render('changePassword', [
631 'model' => $model,
632 ]);
633 }
634
635 protected function setSiteLayout()
636 {
637 $this->layout = 'site';
638 }
639}