• Как хранить логи приложения на php?

    Adamos
    @Adamos
    Альтернатива БД, если лог именно и только для разработчика.
    class Logger
    {
    	private $logfile;
    	private function __construct()
    	{}
    	public function __destruct()
    	{
    		$this->log('');
    		fclose($this->logfile);
    	}
    	public function log($string)
    	{
    		fwrite($this->logfile, $string . "\n");
    		fflush($this->logfile);
    	}
        static public function getCommon($tag)
        {
            $logDir = base_path() . '/../logs/' . $tag; // это в Ларавели, без нее $_SERVER['DOCUMENT_ROOT'] или абсолютный путь (если должно работать в консоли/кроне)
            if(!file_exists($logDir)) {
                mkdir($logDir);
            }
            $logger = new Logger();
            $logger->logfile = fopen($logDir . '/' . date('Y-m-d') . '.log', 'at');
            $logger->log(date('Y-m-d H:i:s') . "\n");
            return $logger;
        }
    }

    Выше корня проекта - папка logs, в ней по подпапкам (определяется в конструкторе логгера) разложены логи того, что происходит. Имя файла сегодняшнего лога - текущая дата, так что легко настраивается чистка по крону и элементарно ищется информация за нужный день.
    Да, это колхоз, нестандарт и животноводство. Но пользоваться этим удобно. Во всяком случае, мне.
    Ответ написан
    2 комментария
  • Push сервер, серверная часть, php+node.js, как правильно реализовать?

    zoonman
    @zoonman
    ⋆⋆⋆⋆⋆
    Первое, это то, что вам нужно разобраться, как именно работают push-уведомления.
    Второе, ненужно порождать лишние компоненты.
    Для PHP тоже имеются решения https://packagist.org/packages/minishlink/web-push

    Для начала вам потребуется понять, что подписки браузеров нужно хранить в отдельной таблице или коллекции в зависимости от вашего основного хранилища.
    Для личных сообщений необходимо будет реализовать опциональную, но включенную по умолчанию связь. Следует помнить о том, что один и тот же пользователь может заходить с разных устройств. Например с десктопа, ноута и таблетки. У одного пользователя может быть несколько подписок.
    Вам потребуется сервер очередей, например RabbitMQ. У вас будет 2 вида задач - публичные и частные.
    Публичная задача - это широковещательная задача, цель которой охватить всех пользователей.
    Например, когда публикуется новый материал на сайте и сайт готов принять всех желающий.
    Для него потребуется простая очередь. Задача воркера будет заключаться в том, чтобы найти всех подписчиков, создать задание для каждого из них и поместить это задание во вторую очередь со множеством воркеров, которые будут непосредственно отправлять пуши.
    Первое задание будет содержать id - материала.
    Второе будет содержать id материала и id подписки.
    Данный подход позволит очереди работать очень быстро. Плюс выборка из базы по id практически мгновенна вне зависимости от движка + отлично кэшируется на уровне самой базы. Доставать из базы нужно только необходимый минимум полей.
    Рассылка личных сообщений может быть сделана на основе второй очереди, дополнив задание несколькими полями. Т.е. воркерам будет все равно что они доставляют.
    Записывать задание со всеми полями для глобальных публикаций не очень хорошая идея, т.к. это будет занимать много памяти и вызывать тормоза. Плюс такое решение не очень хорошо масштабируется.

    Воркеры можно сделать и на Node.js, а можно на PHP. У RabbitMQ есть все необходимое для этого. Можно поискать и другие очереди, однако RabbitMQ достаточно популярное и проверенное решение.
    Ответ написан
    Комментировать
  • Вопрос по Laravel queue, как сделать чтоб очереди выполнялись друг за другом и не пересекались?

    pLavrenov
    @pLavrenov
    Разработка сайтов
    В коробке есть WithoutOverlapping, добавь туда "ключ" группы необходимых задач и они будут выполняться по очереди.
    Ответ написан
    Комментировать
  • Как убрать фолдеры после отправки файлов в laravel + laravel medialibrary?

    @Kostik_1993
    Web Developer
    В MediaLibary нет предварительной загрузки файлов, но ее можно сделать через промежуточную модель
    Вот тут можете подсмотреть реализацию
    Ответ написан
    Комментировать
  • Как переопределять REDIRECT_URI для Laravel Socialite в зависимости от типа аутентифицирующегося пользователя?

    @Eternal97 Автор вопроса
    Решил проблему так:
    Контролер авторизации
    class SocialController extends Controller
    {
        public function index(SocialService $socialService, $client, $provider)
        {
            $socialService->setConfig($client, $provider);
    
            return Socialite::driver($provider)->redirect();
        }
    
        public function callback(SocialService $socialService, $client, $provider)
        {
            $socialService->setConfig($client, $provider);
            $user = Socialite::driver($provider)->user();
            if ($u = $socialService->saveSocialData($client, $user)) {
                Auth::guard($client)->login($u);
                return redirect()->route('profile.index');
            }
    
            return back();
        }
    }

    Сервисный слой:
    use Illuminate\Support\Facades\Config;
    use Illuminate\Support\Facades\Hash;
    
    class SocialService
    {
        public function saveSocialData($client, $user)
        {
            if ($client == 'student') {
                $model = new Student();
            }
            if ($client == 'teacher') {
                $model = new Teacher();
            }
    
            $email = $user->getEmail();
    
            $u = $model->where('email', $email)->first();
    
            if ($u == null) {
                $data = [
                    'first_name' => 'First',
                    'middle_name' => 'Middle',
                    'last_name' => 'Last',
                    'birth' => today(),
                    'email' => $email,
                    'password' => Hash::make('secret123'),
                ];
                return $model->create($data);
            }
    
            return $u;
        }
    
        public function setConfig($client, $provider)
        {
            if ($provider == 'vkontakte') {
                $clientId = env('VKONTAKTE_CLIENT_ID');
                $clientSecret = env('VKONTAKTE_CLIENT_SECRET');
                $redirectUrl = 'http://127.0.0.1:8000/auth/'.$client.'/vkontakte/callback';
            }
            if ($provider == 'google') {
                $clientId = env('GOOGLE_CLIENT_ID');
                $clientSecret = env('GOOGLE_CLIENT_SECRET');
                $redirectUrl = 'http://127.0.0.1:8000/auth/'.$client.'/google/callback';
            }
            Config::set(['services.'.$provider => [
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
                'redirect' => $redirectUrl
            ]]);
        }
    }
    Ответ написан
    Комментировать
  • Как организовать социальную аутентификацию через Socialite(Laravel)+JWTAuth+Vue.js без редиректа с API-сервера?

    dlnsk
    @dlnsk
    ПК Партнер 01.01 -> ПК Поиск -> IBM PC
    Работает у меня такая схема и в Ionic и в NativeScript.
    В общем схема везде одинаковая.
    Ionic:
    На Laravel нужен Socialite, на клиенте что-то в соответствии с фреймворком. Я использовал ng2-ui-auth. Еще вам нужно установить плагин InAppBrowser.
    Последовательность такая:
    1. В своем приложении вы жмете на кнопку "Войти через GitHub"
    2. Открывается InAppBrowser окно входа GitHub (в урле передается clientId вашего приложения и redirectUri, за это отвечает ng2-ui-auth).
    2а. Обратите внимание что redirectUri из запроса должен быть идентичен Authorization callback URL в настройках вашего приложения на сайте GitHub (Settings / Developer settings / OAuth Apps) и в случае Cordova должен быть равен "localhost:3000".
    3. GitHub авторизирует вас по логину/паролю, спросит разрешения передавать данные Приложению и редиректит страницу на redirectUri добавляя к нему токен.
    4. ng2-ui-auth перехватывает обращение к localhost:3000 (это делается с помощью JS, тут нет никакого локального сервера), достает токен и пересылает его на конечный url (указывается для каждого провайдера в настройках ng2-ui-auth).
    4а. Вот этот конечный url должен быть адресом вашего backend'а, а именно метода, который с помощью Socialite будет запрашивать данные пользователя у GitHub.
    5. С помощь Socialite вы получаете данные о пользователе у GitHub. Создаете пользователя в Laravel, если его нет, и делаете любые другие необходимы действия.
    6. Используя данные пользователя с помощью jwt-auth создаете jwt-токен и возвращаете его клиенту (в пункт 4).
    7. На клиенте запоминаете jwt-токен и тот факт, что пользователь аутентифицирован. Из ответа можете достать email (если вы его передали) и где-нибудь отобразить.
    Все!

    С NativeScript все абсолютно аналогично (там на клиенте я использую nativescript-oauth2) за исключением одного: в NS нет webview, поэтому перехват redirectUri выглядит по-другому:
    1. В Authorization callback URL на GitHub вы пишите что-то вроде blablabla://auth (вместо blablabla какая-то длинная уникальная строка - urlScheme).
    2. Эта urlScheme также пописывается в настройках nativescript-oauth2 и в App_Resources/Android/src/main/AndroidManifest.xml в виде intent-filter
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="blablabla" />
    </intent-filter>

    Приложение перехватывает обращение к этой уникальной urlScheme и дальше все продолжается согласно списка.
    Ответ написан
    1 комментарий
  • Как правильно выстроить разработку и деплой сайта?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Разработка и контроль версий

    Читаем про git flow, восхищаемся и интегрируем.
    Читаем PSR-ы, восхищаемся и интегрируем. Не помешает: Попросили проверить код, на что смотреть нужно?
    Читаем про vagrant. На базе вот этого вот строим dev окружение. Можете поиграть с https://puphpet.com/. До docker все же стоит дорасти.
    Постигаем Phpstorm, и радуемся жизни.
    Можете посмотреть так же: https://github.com/index0h/php-conventions

    Тестирование

    Читаем про phpunit, восхищаемся и интегрируем.

    Документирование

    Рекомендую взять за правило: документирование алгоритмов нужно только в крайнем случае, когда используются некие хаки. Говнокод лучше переписать на что-то очевидное, чем объяснять, какая муха вас укусила и где.
    Что касается docblock-ов для помощи ide - это отличная идея.

    Деплой

    Самый простой и надежный способ: root у вашего nginx/apache указывать как ссылку на каталог текущей прод версии. При релизе - заливать код с помощью rsync в новый каталог, а далее менять ссылку на новый релиз.
    Например у вас каталог с версиями кода:
    production -> v1.0.2 - текущая версия
    v1.0.1 - старый релиз
    v1.0.2 - текущая версия
    v1.0.3 - новый релиз
    Когда подготовка завершена - вы только меняете симлинк production на v1.0.3. Если что не так - можно быстро откатиться на предыдущую версию.
    Ответ написан
    11 комментариев