• Существует ли ресурс, на котором хорошо написано про паттерны (с примерами)?

    Vincent1
    @Vincent1
    Доступно ->
    Дизайн-патерни — просто, як двері
    designpatterns.andriybuday.com
    Ответ написан
    Комментировать
  • С помощью чего писать тесты для сайта?

    @hubramubr
    Не пишешь тесты - ты плохой программист?
    Это от задачи зависит. Автоматизированное тестирование - это вещь. Но на недорогих проектах обходятся без этого.

    Есть тесты серверной части, есть тесты JS, есть тесты функциональные, есть юнит-тестирование. Они все пишутся по разному и на разном.

    Ну, например, Selenium используется для тестов с эмуляцией пользователя.
    А методика юнит-тестирование как правило описана в документации к используемым инструментам.
    Ответ написан
    1 комментарий
  • В чем суть роутера на php?

    onqu
    @onqu
    weasy
    1. Здесь пугают всякими контроллерами, ларавелями. Давайте жить проще. Для начала дадим определение модному слову роутер. Это маршрутизатор. Что делает маршрутизатор? Правильно. Обрабатывает маршруты, являясь связующим звеном. Маршрутом для web сайта принято считать метод запроса [GET, POST, PUT и другие] и компоненты URI.

    например: https://ru.wikipedia.org/wiki/URI?foo=bar#title
    [схема: https] :// [источник: ru.wikipedia.org] [путь: /wiki/URI] [запрос: ?foo=bar] [фрагмент: #title]


    Но для определения маршрута может браться любая другая информация передаваемая серверу, определение выше это лишь наиболее употребляемые параметры.

    Сама работа, как правило проста: от клиента приходит запрос, маршрутизатор перебирает все заданные ему пути до первого совпадения. При совпадении вызывается определенная вами функция, которая возвращает ответ клиенту.

    2. Он необходим, если в приложении одна точка входа, когда любой запрос приходит на один файл.

    3. Простой пример
    // файл index.php
    
    // Маршруты
    // [маршрут => функция которая будет вызвана]
    $routes = [
        // срабатывает при вызове корня или /index.php
        '/' => 'hello',
        // срабатывает при вызове /about или /index.php/about
        '/about' => 'about',
        // динамические страницы
        '/page' => 'page'
    ];
    
    // возвращает путь запроса
    // вырезает index.php из пути
    function getRequestPath() {
        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    
        return '/' . ltrim(str_replace('index.php', '', $path), '/');
    }
    
    // наш роутер, в который передаются маршруты и запрашиваемый путь
    // возвращает функцию если маршшрут совпал с путем
    // иначе возвращает функцию notFound
    function getMethod(array $routes, $path) {
        // перебор всех маршрутов
        foreach ($routes as $route => $method) {
            // если маршрут сопадает с путем, возвращаем функцию
            if ($path === $route) {
                return $method;
            }
        }
    
        return 'notFound';
    }
    
    // функция для корня
    function hello() {
        return 'Hello, world!';
    }
    
    // функция для страницы "/about"
    function about() {
        return 'About us.';
    }
    
    // чуть более сложный пример
    // функция отобразит страницу только если
    // в запросе приходит id и этот id равен
    // 33 или 54
    // [/page?id=33]
    function page() {
    
        $pages = [
            33 => 'Сага о хомячках',
            54 => 'Мыши в тумане'
        ];
    
        if (isset($_GET['id']) && isset($pages[$_GET['id']])) {
            return $pages[$_GET['id']];
        }
    
        return notFound();
    }
    
    // метод, который отдает заголовок и содержание для маршрутов,
    // которые не существуют
    function notFound() {
        header("HTTP/1.0 404 Not Found");
    
        return 'Нет такой страницы';
    }
    
    
    // Роутер
    // получаем путь запроса
    $path = getRequestPath();
    // получаем функцию обработчик
    $method = getMethod($routes, $path);
    // отдаем данные клиенту
    echo $method();


    На практике используют более сложные маршрутизаторы, у которых гораздо большие возможности.

    4. Обойтись без него можно. Если каждая страница в вашем приложении будет являться отдельным файлом, который отвечает за отдачу информации.
    index.php
    about.php
    contact.php
    ...


    Это олдскульная структура, в новых проектах почти не применяется.
    Ответ написан
    13 комментариев
  • Где брать красивые фоны для сайтов?

    Sanes
    @Sanes
    Белый фон, беспроигрышный вариант. Можно разбавить чем-то таким.
    Ответ написан
    Комментировать
  • CMS для музыкальной социальной сети?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Вы собираетесь сделать клон вконтакта, только кривой. А так как речь идет о поиске CMS - то денег на разработку у вас нет. А стало быть нет денег на маркетинг. А стало быть.... ну короче зачем продолжать?

    Сделать MVP на CMS можно только из расчета найти инвесторов что бы заплатить за разработку реального продукта. Реальность такова что такие проекты намного дешевле в последствии писать сразу на фреймворках, вроде laravel или symfony, и потом уже дальше подкручивать расширяя команду разработки.

    Словом... удачи с вашей задумкой, но это проигранная битва.
    Ответ написан
    7 комментариев
  • Куда направлена тенденция, от веб к платформам или наоборот?

    xmoonlight
    @xmoonlight
    https://sitecoder.blogspot.com
    Приоритеты (к сожалению) такие, но хотелось бы чтобы они шли в обратном порядке:
    1. Максимальная скорость разработки
    2. Максимальный доход за наименьший промежуток времени
    3. Быстрый охват большего количества платформ.
    4. Простота поддержки разработанного решения.
    5. Скорость работы клиентского приложения и удобство для пользователя.

    При обратном порядке - я готов платить за каждое приложение!

    Т.е. тенденция при таком порядке - это webkit/HTML5.
    А при обратном - это с учетом всех особенностей: под каждую платформу - своё приложение.
    Ответ написан
    Комментировать
  • Как урезать свой перфекционизм?

    SynCap
    @SynCap
    Делаю интернет с 1998 года
    Столько комментариев не видел ни в одном ответе.
    Сразу напрашивается вывод о соотношении урезанного перфекционизма к профессионализму.

    Сам прокристинатор со стажем, поэтому не буду давать советы, а приведу цитаты:
    Кот ежедневно вылизывает свое хозяйство, а профи сразу делает хорошо. Если сделано нехорошо, значит не профи, возможно, опыт этого проекта сделает тебя профи на следующем проекте. (старый препод по проектированию микропроцессоров, никогда не знал его фамилию)
    Опыт сын ошибок трудных, а гений - парадоксов друг. (А.Пушкин)
    Лучшее - враг хорошего, давно сказано (народная мудрость)
    А хорошее всегда полезно (т.е. работает) - давно замечено, нужное всегда просто, непростое - не нужно. (Михаил Калашников). И того же источника: простое сделать всегда сложнее, а сложное сделать гораздо проще.
    Профессионала отличает выбор инструмента и отношение к нему. (А. Макаренко)
    Правильно организованный процесс - хороший повод для успеха. (Генри Форд) и того же источника самую знаменитую фразу про цвет автомобиля переделаем: Рефакторинг может быть любой величины, главное, чтобы это был 0.
    Хорошее дело браком не назовут (немного не в тему, но в нашем случае - подойдет)

    В основном согласен с остальными специалистами по перфекционизму и прокристинации: главное следование цели в установленные сроки. Это наука, а как это сделать - уже исскуство, для которого нужны воля и талант. :)

    Успехов всем и не вешать нос!
    Ответ написан
    2 комментария
  • Возможна ли переквалификация в разработчики после 30 без профильного высшего образования?

    trevoga_su
    @trevoga_su
    > программирование - это наверное тот профиль деятельности, которым я могу с интересом заниматься даже в свободное от работы время

    Что и требовалось доказать. Это сейчас для тебя программирование это так, прикольчик, хобби.
    А в итоге тебе придется заниматься той же аналитикой + кодингом, ибо в программирование сбор бизнес требований - это почти неотъемлемая часть работы программистов, особенно если вы работаете в серьезных компаниях с долгоиграющими проектами, где постоянно меняются правила бизнеса.

    В итоге ты будешь тем же аналитиком + копаться в куче гов... кода.
    Ответ написан
    Комментировать
  • Как урезать свой перфекционизм?

    isqua
    @isqua
    Научу HTML, CSS, JS, BEM и Git
    Чтобы перестать делать лучше то, что ещё не сделано до конца, нужно понять одну простую истину: Запущенный проект лучше, чем не запущенный.

    Давайте потренируемся:
    • Что лучше: запущенный проект с несжатыми стилями или незапущенный со сжатыми?
    • Что лучше: не запущенный проект с десятью страницами или запущенный с тремя?
    • Что лучше: запущенный проект c jQuery или не запущенный без jQuery?


    Надеюсь, вы смогли выбрать! Как узнать, что пора запустить проект? (Под запуском я имею в виду «показать людям». Например, если вы решили написать библиотеку, давайте считать «проект запущенным», если вы выложили её на гитхаб) Нужно прикинуть, сколько времени вам надо на разработку и умножить на два. Если получилось больше двух недель, то стоит разбить проект на части и прикинуть так про каждую часть. Соответственно, ставите дедлайны.

    Промежуточные дедлайны помогают успеть к последнему. Старайтесь сначала реализовать основную функциональность, а потом дополнительную. Если не успеете к дедлайну доделать дополнительное — сначала запустите основное, а потом видно будет, надо ли вообще доделывать дополнительное.

    Ну и не беритесь за каждую идею, а выбирайте самые инетересные. Если вы будете делать пять проектов одновременно, скорее всего ни один не доделаете.

    Удачи!
    Ответ написан
    4 комментария
  • Как сделать уникальные просмотры статей по IP адресу?

    Узнаем IP пользователя:

    if (!empty($_SERVER['HTTP_CLIENT_IP'])){
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else{
        $ip = $_SERVER['REMOTE_ADDR'];
    }


    Предположим, что человек решил обновить страницу, но IP уже есть в вашей базе, следовательно остается только проверить на соответствие и в случае совпадения не засчитывать просмотр.

    $query = mysql_query("SELECT `ip` from `table` where `ip` = '$ip'");
    mysql_fetch_array($query);
    if(isset($query['ip'])){
        // Если ip есть, то не засчитываем
    }else{
        // Иначе засчитываем посещение и делаем sql запрос для увеличение счетчика
    }

    Вы наверное поняли, что для IP адресов вам нужно создать отдельную таблицу в БД и записывать их туда когда пользователь зайдет на страницу в первый раз и тогда после обновления страницы вы уже будете знать, что данный человек посещал страницу.

    Возможно у вас возникнет вопрос об определении IP адреса, мол зачем там аж три разных варианта получения ip. Тык вот $_SERVER['HTTP_CLIENT_IP'] и $_SERVER['HTTP_X_FORWARDED_FOR']) содержат реальный ip адрес пользователя, то есть, если он зайдет к вам, используя прокси сервер, то вы получите не ip прокси, а ip его компа. Но на случай, если в этих двух переменных не будет ip адреса, то воспользуемся $_SERVER['REMOTE_ADDR'].

    Есть еще вариант реализации с привязкой к кукки. Почитайте и попробуйте. Принцип тот же.

    Я думаю, достаточно информации для того, чтобы вы сейчас пошли и сделали уникальный просмотр по IP адресам. Так что дерзайте :). А вообще почитайте о том, как лучше делать уникальные просмотры, ибо делать только по ip адресу не есть корректно.
    Ответ написан
    8 комментариев
  • Как в yii2 сгруппировать результат запроса по дате (timestamp)?

    @matperez
    Попробуйте что-нибудь вроде
    ->select('article.*, DATE_FORMAT(FROM_UNIXTIME(`article.sort_date`), \'%d.%m.%Y\') as date')
    ->orderBy('sort_date')

    Ну и публичное свойство date можно в модель добавить чтобы было куда само значение сохранять.

    А раскидать в массив по конкретным датам можно уже на уровне PHP.
    Ответ написан
    Комментировать
  • Yii2 как сделать связь один к одному?

    MegaMufa
    @MegaMufa
    В таблице пользователя прописываете связь:
    public function getProfile() {
      return $this->hasOne(Profile::class,['id'=>'id']);
    }


    И профиль становится доступным через свойство.
    $user = User::find()->andWhere(['username'=>$login])->one();
    $user->name; // своятво пользователя
    $user->profile->id // свойство профиля


    Если хотите одним запросом, то при выборке укажите модель, которую тянуть
    $user = User::find()->with('profile')->andWhere(['username'=>$login])->one();
    Ответ написан
    Комментировать
  • Нормализация БД. Зло или добро?

    @maxkoryukov
    Родился, тусуюсь
    Давайте разбираться.

    В нормализованной бд (в общем случае) выборка по произвольным параметрам будет работать пошустрее. Проще добавлять и изменять данные.
    Ненормализованная может дать очень большой выигрыш для четко очерченного круга запросов по выборке данных (не нужны лишние джойны, уже готова сортировка и прочее). Но если вам понадобится что-то нестандартное - готовьтесь к любому исходу. Скорей всего запрос будет работать очень медленно.

    В нормализованной БД, запрос до определенной степени можно оптимизировать. Я видел, как хранимая процедура (очень большая) ускорялась с 2 часов до 5 минут с помощью подходящих индексов и правильных джонов, но оптимизацию проводил SQL-кунг-фу сэнсэй, он знал, что покрутить.
    В денормализованной - вы так уже не сделаете, придется менять структуру данных.

    Я бы старался нормализовать данные, но не до академического фанатизма, а до той степени, когда таблицы не вызывают отвращения ни у меня, ни у оптимизатора запросов используемой СУБД.
    Ответ написан
    Комментировать
  • Нормализация БД. Зло или добро?

    Therapyx
    @Therapyx
    Data Science
    По мне так - везде найдется тот, кто будет критиковать даже самый лучше вещи в мире.
    И вот это видимо и есть такой случай. Ниразу не видел, чтобы нормализацию выставляли в плохом свете. Конечно, если ваш проект, программа на столько маленькая, что можно обойтись и без нормализации и при этом останется такое же удобство, быстродейственность, то это да - нормализация мб и не нужна. Но у проектов есть чудесное свойство, а именно развиваться :) И вот лучше такие вещи продумывать заранее, ежели потом держаться за голову.
    Ответ написан
    4 комментария
  • Зачем нужны таск менеджеры GULP и GRUNT?

    Tash1moto
    @Tash1moto
    Примерно лет 10 назад, помню было .html .css .js

    Сейчас же, весь этот "девелоперский" антураж в виде фреймворков для фреймворков для запуска фреймворков с кучей json конфигов, с пафосным названием и флэт логотипом : )
    Ответ написан
    1 комментарий
  • Как организовать загрузку файлов в форме?

    vakorovin
    @vakorovin
    Разработчик
    Здравствуйте! Не раскрыли вы полностью ваш вопрос, но постараюсь ответить, исходя из наших проектов на yii2.
    Если используется механизм, при котором файлы можно прикреплять на этапе создания некой модели (скажем Portfolio), и загружаются они сервер посредством ajax-запроса (к примеру https://github.com/hayageek/jquery-upload-file), то возникает ситуация, что привязываться то еще не к чему (объект класса Portfolio еще не сохранен), а файлы уже на сервере. На этот случай используем поле hash, значение которого уникально, и именно по нему привязываются файлы. Т.е. при создании нового объекта Portfolio сразу генерируем уникальный hash, передаем его в форму создания, и с ним грузим аяксом файлы. При желании можно повесить cron-задачу для удаления из файловой системы файлов, которые привязаны к несуществующему Portfolio.hash.

    Далее, сама модель. Берем официальную документацию:

    https://github.com/yiisoft/yii2/blob/master/docs/g...

    Расширяем как нам угодно, например так:

    class File extends \yii\db\ActiveRecord
    {
        public $file;
    
        public function rules()
        {
            return [
                [['file'], 'file'],
                [['filename', 'parent_id'], 'required'],
                [['parent_id'], 'integer'],
                [['filename', 'path'], 'string', 'max' => 255],
                [['description'], 'string']
            ];
        }


    Далее, в контроллере как себя вести, описано как раз по ссылке выше, но в нашем случае суть такова - для каждой новой модели (об этом чуть позже) получаем сам файл:

    $model = new File();
            $model->file = UploadedFile::getInstance($model, 'file');


    и назначаем все остальные параметры, будь то parent_id или что-то еще (включая генерацию нового имени для хранения в файловой системе). Далее, если модель проходит валидацию - сохраняем ее в БД и сохраняем файл в файловой системе:

    if ($model->file && $model->validate()) {                
                $model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
            }


    Одно уточнение. Если загружать файлы по одному, и только в форме показывать несколько полей, то это решается средствами js, повесить кнопку для создания очередных fileInput с именем File[][file] и textInput File[][description] - проблем не составит. А вот если требуется закинуть их сразу пачкой, то выходов 2 - либо как в указанном по ссылке примере - в одной модели разрешить мультизагрузку, и уже из нее (после валидации) создавать нужные вам модели, либо (что мне кажется логичнее) играться с методом formName(), который будет возвращать нужное имя аттрибута из формы.

    Т.е. в базовом случае поля формы имею имена File[file], File[description], File[id]. В нашем же случае получаются такие имена:

    File[0][file], File[0][description], File[0][id];
    File[1][file], File[1][description], File[1][id];
    File[2][file], File[2][description], File[2][id];


    Теперь в контроллере в цикле проходим

    foreach (Yii::$app->request->post('File') as $sn => $file){
            $model = new File;
            $model->fakeFormName = "File[{$sn}]";
            $model->file = UploadedFile::getInstance($model, 'file');
        }


    В примере выше мы заранее создали свойство $fakeFormName, в которое поместим требуемое для каждого случая базовое имя полей формы и вернем его значение в методе formName(), в таком случае UploadedFile::getInstance($model, 'file') сработает как надо.

    Уф, не знаю, насколько доходчиво разъяснил, что-то может потерял в потоке сознания, но думаю основную суть и опорные точки разъяснил. Если что-то непонятно, отпишитесь, я распишу подробнее (проектов на Yii2 много, все включают работу с файлами в той или иной степени, есть разные реализации, в том числе прямо сейчас пишем файловый менеджер для нашей админки на yii2).
    Ответ написан
    Комментировать
  • Куда двигаться в веб-разработке?

    cyberyak
    @cyberyak
    Куда двигаться в веб-разработке? - Подальше от России
    Ответ написан
    Комментировать
  • Поможет ли такой php-код защититься от sql-инъекций и XSS, какие в нём есть уязвимости?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Все что делает этот идиотский код - это портит входящие данные.
    Я даже не знаю, стоит ли объяснять. Ведь 100500 раз уже объясняли.

    Но самый, конечно ад - это ответы.

    Когда начинаешь этим щеночкам объяснять, что такое инъекция, и как от нее защититься, все начинают шипеть - "да знаем уже, учоные!". Но когда доходит до дела - такой ад выдают, что становится понятно. Не учёные, а все те же обезьяны, которые вызубрили пару заклинаний, но по традиции не понимают, ни как эти заклинания работают, ни для чего они нужны.

    Тем, кто предлагает отрезать кавычки от quote, надо самим что-нибудь отрезать.

    И это неловкое чувство, когда 2015 году слышишь самую заветную мантру мадагаскарских гамадрилов: "mysql_real_escape_string зашышает от ынъекцый!". Стоит, блин, такой "устаревший", но еще крепкий архангел с пылающим мечом, и разит супостата прямо в темечко - вот так представляет себе принцип работы этой функции средний пользователь похапе.
    Ответ написан
    Комментировать
  • Как защитить исходный код стартапа от воровста программистом, которые его пишет?

    @iliyaisd
    На моей практике было два варианта:
    1. Часть кода шифровалась, мне предоставлялся доступ только к нужной папке ftp и к нужному модулю, основной движок лежал отдельно. Всё это происходило на тестовом сервере, так что боевую БД я бы не снёс.
    2. По сути то же, но проще: на каждом сервере свой конфиг доступа к БД, права выноса кода на релиз у меня нет - только делаю коммит, после отмашки тестировщика. Чекаут только нужных проектов и библиотек. Коммит можно делать тоже только туда, куда надо.

    Защита самого кода встречается крайне редко, потому что код, как правило, типовой, и можно без труда найти/написать модули для всего. Гораздо важнее отгородить доступ к данным (БД и другие файлы - картинки, звуки и т.п.), хотя при желании и это можно спарсить. Самое ценное - это клиенты, продажи, и прочее. Без доступа к коду и данным достаточно легко сделать клон почти любого проекта, но без продаж, рейтингов и клиентской базы - он вам не конкурент.
    Ответ написан
    Комментировать
  • Yii2 PJax почему страница все равно перезагружается?

    @Zohei
    нужно указать 'format'=>'raw',
    www.yiiframework.com/doc-2.0/yii-grid-datacolumn.h...
    [
                'class'=>'yii\grid\DataColumn',
                'attribute'=>'name',
                'format'=>'raw',
                'value'=>function ($model, $key, $index, $column) {
                    return a($model->name, ['update','id'=>$model->name], ['data-pjax'=>0]);
                },
                'contentOptions'=>[
                    'class'=>'edit-link',
                ],
            ],
    Ответ написан
    Комментировать