Вы видите копию треда, сохраненную 23 июня 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>479598
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП отвечает даже на самые нубские вопросы. ОП заходит где-то раз в день-два, не жди его, решай задачки дальше.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Учебник дает основы языка PHP, но чтобы делать сайты, этого недостаточно. Если ты его прошел, то надо переходить в более серьезным задачкам, которые научат тебя как выдавать страницы в браузер, работе с таблицами в БД, работе с формами, MVC.
- Простая, но полезная задача сделать список студентов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/Doctrine 2
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://gist.github.com/codedokode/10774100
https://gist.github.com/codedokode/7054af4a03865c4cc863
Может тебе понадобится пользоваться командной строкой, вот гайд https://gist.github.com/codedokode/10539568
Вот небольшой туториал по тому как начать использовать PHP на сервере для отдачи странички в браузер: https://php.net/manual/ru/tutorial.php Увы, уроков плавно подводящих к тому, как сделать задачи выше, пока нет, так что если что, задавай вопросы.
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://gist.github.com/codedokode/10539213
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.github.io/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git:
Подскажи сайты для поиска работы, я не умею гуглить? brainstorage.me, geekjob.ru, hh.ru
Нужен ли ООП, фреймворки, MVC? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.net/45000175
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Где искать работу и заказы — hh.ru, geekjob.ru, brainstorage.me, fl.ru, odesk.com. Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
http://hh.ru/vacancy/12818549
http://hh.ru/vacancy/12953702
>а алгоритмы знать надо? математику там?
Ты хочешь видео цифровать (интересно, на PHP это кто-нибудь делает?) или говносайты клепать? Зависит от области.
В одном могу порадовать: писать сортировку массивов не придется.
во всех нормальных компаниях ебут алгоритмами/матешей
поэтому и спрашиваю
> писать сортировку массивов не придется.
сортировки в школах пишут
Ну раз во всех "нормальных" компаниях требуют, а сортировки в школах пишут, то да, придется знать "алгоритмы, и математику там".
Гуглил «алгоритмы и структуры данных»? Там каие-то видеоллекции и древняя книжка есть. А, вспомнил, пару тредов назад тот же вопрос был, копипаста:
--------------------
Вот я нашел какие-то видеолекции (хотя я сам не очень люблю такой формат да и лекторы там не идеальные):
https://www.lektorium.tv/course/22823
http://habrahabr.ru/company/abbyy/blog/251561/
Есть такая книга но она очень старая, не уверен, стоит ли на нее время тратить: http://snilit.tspu.ru/uploads/files/default/virt.pdf
Есть такая интересная книга, может быть ее стоит почитать: http://aliev.me/runestone/ — она использует Питон для примеров, но это не принципиально, ты можешь те же алгоритмы на любом языке реализовать.
Это по моему как раз книга начинающего уровня.
Если тебе интересна книга топового уровня то это конечно 7-томник Дональда Кнута «Искусство программирования» . Я когда-то даже первые 200 страниц по моему прочел но ничего не помню.
Также, ты можешь поискать книги про решение олимпиадных задач. Там тоже разные алгоритмы описываются.
Алсо смотри у нас есть задачки потренироаться: https://github.com/codedokode/pasta/blob/master/interview-tasks.md
Благодаря тебе и твоему сайту я изучил php, потом пошли и другие языки. Сегодня я дембельнулся (1.5 года служил).
Сейчас планирую вспомнить все свои знания и искать работу. Надеюсь мир технологий станет частью моей жизни, ведь я получаю от этого кайф.
>Один раздел сайта = 1 контроллер обычно.
Принимаю пока за аксиому.
> если у тебя есть модель новостей то скорее всего понадобится и раздел новостей и контроллер для их отображения (хотя может ты их просто сбоку выводишь на других страницах и тогда отдельный контроллер не нужен)
Ага, то есть если у меня на одной странице ("разделе"?) выводятся разные сущности, то один контроллер сможет работать с несколькими моделями, обрабатывающими эти сущности.
>Согласен в руководстве написано плохо.
Приятная неожиданность. Я уж думал как обычно назовете ленивым/тупым/быдлокодером и т.д.
Начинающим реально сложно учиться по мутным справочникам и документациям. Лингвист, знающий 4-5 языков, без проблем осилит пятый-шестой по словарю и грамматике. Но дети в школе учатся не так.
>Вот еще моя мини-паста про MVC:
Вопрос скорее по архитектуре приложения, а не по самому mvc. То есть не как разбить код на модель-вид-контроллер, а как определить, какие у нас есть модели, и какие контроллеры.
Ну хорошо, частично прояснилось. Но может быть я понял не так, попробуем на практическом примере.
Вот я собираюсь делать сайт, на котором будут доступны следующие действия:
1. Логин и регистрация.
2. crud для записей/постов блога.
3. crud для фото, отличается от п.2 загрузкой файлов на сервер, а также другим представлением
4. Комментарии к постам блога и к фото.
5. Лайки к постам/фото.
6. Страница с выводом топ-100 самых активных/популярных по статистике пользователей (order by кол-во лайков полученных/поставленых, или по общему кол-во загруженных на сервер фотографий).
7. Возможно еще что-нибудь, у меня не хватает фантазии придумать.
Итак, какие у нас тут модели? Я думаю, Post (для новостей в блоге), Photo, Comment, Like - это модели, соответствующие таблицам базы (yii использует Active Record). Для формы логина и регистрации использовать модели, унаследованные от CFormModel (LoginForm extends CFormModel, RegisterForm extends CFormModel).
Контроллерами будут PostController (для страницы с новостями), PhotoController (для страницы с галереями). Если вздумается на одной странице делать и вывод новостей, и галерею фото, то делаем один контроллер. Хз как его тогда назвать, какой-нибудь PostAndPhotoController, или тупо MainController, этот контроллер может взаимодействовать и с моделью Post, и с Photo, и с Comment (если на главной под новостью будут отображаться скажем три последних камента, как на борде).
Нужно ли создавать тогда отдельный контроллер для комментариев, если у меня будет страница с просмотром новости с комментариями (как на хабре, например, где камменты занимают больше места, чем сама статья)? Ведь это скорее post/view&id=6651, то есть экшн контроллера новостей (Post).
Я так понимаю, что контроллер для комментариев есть смысл делать только ради админки, где у нас будет возможность их редактирования/удаления?
Так, а что делать со статистикой? Вот я хочу чтобы была ссылка, по нажатию на которую открывалась страница с выводом всяких топ-10, топ-100 по разным показателям.
Топ-100 самых популярных пользователей (кол-во лайков, полученных на постах + на фотографиях). Топ-100 самых активных юзеров (больше всего лайков отдано).
Топ-еще-какая-то-хуйня. Все таблички на одной странице. Делать StatisticController, который будет использовать все необходимые модели?
>Один раздел сайта = 1 контроллер обычно.
Принимаю пока за аксиому.
> если у тебя есть модель новостей то скорее всего понадобится и раздел новостей и контроллер для их отображения (хотя может ты их просто сбоку выводишь на других страницах и тогда отдельный контроллер не нужен)
Ага, то есть если у меня на одной странице ("разделе"?) выводятся разные сущности, то один контроллер сможет работать с несколькими моделями, обрабатывающими эти сущности.
>Согласен в руководстве написано плохо.
Приятная неожиданность. Я уж думал как обычно назовете ленивым/тупым/быдлокодером и т.д.
Начинающим реально сложно учиться по мутным справочникам и документациям. Лингвист, знающий 4-5 языков, без проблем осилит пятый-шестой по словарю и грамматике. Но дети в школе учатся не так.
>Вот еще моя мини-паста про MVC:
Вопрос скорее по архитектуре приложения, а не по самому mvc. То есть не как разбить код на модель-вид-контроллер, а как определить, какие у нас есть модели, и какие контроллеры.
Ну хорошо, частично прояснилось. Но может быть я понял не так, попробуем на практическом примере.
Вот я собираюсь делать сайт, на котором будут доступны следующие действия:
1. Логин и регистрация.
2. crud для записей/постов блога.
3. crud для фото, отличается от п.2 загрузкой файлов на сервер, а также другим представлением
4. Комментарии к постам блога и к фото.
5. Лайки к постам/фото.
6. Страница с выводом топ-100 самых активных/популярных по статистике пользователей (order by кол-во лайков полученных/поставленых, или по общему кол-во загруженных на сервер фотографий).
7. Возможно еще что-нибудь, у меня не хватает фантазии придумать.
Итак, какие у нас тут модели? Я думаю, Post (для новостей в блоге), Photo, Comment, Like - это модели, соответствующие таблицам базы (yii использует Active Record). Для формы логина и регистрации использовать модели, унаследованные от CFormModel (LoginForm extends CFormModel, RegisterForm extends CFormModel).
Контроллерами будут PostController (для страницы с новостями), PhotoController (для страницы с галереями). Если вздумается на одной странице делать и вывод новостей, и галерею фото, то делаем один контроллер. Хз как его тогда назвать, какой-нибудь PostAndPhotoController, или тупо MainController, этот контроллер может взаимодействовать и с моделью Post, и с Photo, и с Comment (если на главной под новостью будут отображаться скажем три последних камента, как на борде).
Нужно ли создавать тогда отдельный контроллер для комментариев, если у меня будет страница с просмотром новости с комментариями (как на хабре, например, где камменты занимают больше места, чем сама статья)? Ведь это скорее post/view&id=6651, то есть экшн контроллера новостей (Post).
Я так понимаю, что контроллер для комментариев есть смысл делать только ради админки, где у нас будет возможность их редактирования/удаления?
Так, а что делать со статистикой? Вот я хочу чтобы была ссылка, по нажатию на которую открывалась страница с выводом всяких топ-10, топ-100 по разным показателям.
Топ-100 самых популярных пользователей (кол-во лайков, полученных на постах + на фотографиях). Топ-100 самых активных юзеров (больше всего лайков отдано).
Топ-еще-какая-то-хуйня. Все таблички на одной странице. Делать StatisticController, который будет использовать все необходимые модели?
Возьми info-zip или 7-zip и с командной строки шифруй файлы.
>Так, а что делать со статистикой?
Складывать все события в таблицу и тащить из неё данные запросами с группировкой. Над ними тоже контроллер и вьюхи написать.
Но скорее всего, тебе потребуется входящая статистика, т.е. заходы из поисковых машин. Там проще Spylog или HotLog поставить. Ну или руками парсить лог-файлы (текстовые).
http://rutracker.org/forum/viewtopic.php?t=5005285
http://yiiframework.ru/doc/guide/ru/form.model
$model=new LoginForm;
if(isset($_POST['LoginForm'])) $model->attributes=$_POST['LoginForm'];
>Последнее выражение в примере как раз и является массовым присваиванием, где значение каждой переменной в $_POST['LoginForm'] присваивается соответствующему атрибуту модели.
Я не понял, как при присваивании свойству attributes массива из пост его значения раскидываются по одноименным свойствам userName, password, rememberMe?
Добросовестно открыл исходный код класса модели CFormModel, пытаюсь найти там этот загадочный кусок кода.
А, вот что-то нашел: подозреваю что этим раскидыванием массива по свойствам объекта занимается метод getIterator, который возвращает объект класса CMapIterator, который... ну вот, я запутался.
Ну почитай. Ты же ничего не теряешь. Только будь готов, что знания по php, mysql, js, css занимают больше 688 страниц. Ты охуеешь, насколько больше.
объема не боюсь, с html и css уже знаком, а вот по php mysql js хочу базовые навыки получить
На следующей странице http://yiiframework.ru/doc/guide/ru/form.action
>Свойство attributes определяется классом CModel, который ожидает получить массив пар имя-значение, чтобы затем присвоить каждому атрибуту модели соответствующее значение.
Лезу в класс CModel.
А, вот. Здесь есть метод setAttributes, внутри которого в форыче происходит установка одноименных свойств.
foreach($values as $name=>$value)
\t\t{
\t\t\tif(isset($attributes[$name]))
\t\t\t\t$this->$name=$value;
\t\t\telseif($safeOnly)
\t\t\t\t$this->onUnsafeAttribute($name,$value);
\t\t}
Ну что ж, это было чрезвычайно познавательно и увлекательно, что я могу сказать.
ОП, накидай пожалуйста каких-нибудь ссылок по паттернам (или как это называется) типа геттеров-сеттеров, итераторов и прочей хуиты.
Это хорошо что ты смотришь в код. Это полезно.
attributes это не настоящее свойство. Там используется магический метод _ _ get, поищи его. Мануал http://php.net/manual/ru/language.oop5.overloading.php#object.get
При его использоании помни что ты не должен давать перезаписать критические поля вроде флага isAdmin у пользователя, а то найдется умник который добавит в _POST значение isAdmin=1 и поставит себе права администратора. Так по моему гитхаб взломали в свое время.
> подозреваю что этим раскидыванием массива по свойствам объекта занимается метод getIterator, который возвращает объект класса CMapIterator, который
Итератор используется когда ты пытаешься применить цикл foreach к объекту. Ты можешь с помощью getIterator определить что именно будет перебирать цикл, мануал:
http://php.net/manual/ru/class.traversable.php
Итератор вообще это объект который что-то перебирает или обходит.
Полистал 4-е издание. Не трать время, лучше учебник ОПа. Там код в итоговом проекте из начала нулевых. ОП тут с таким активно борется. В остальном пересказ мануалов своими словами.
> Начинающим реально сложно учиться по мутным справочникам и документациям.
Привыкай, мутную документацию придется читать еще не раз. Конечно, если у тебя был опыт с чем-то похожим то читать было бы легче.
> то один контроллер сможет работать с несколькими моделями, обрабатывающими эти сущности.
да
> Контроллерами будут PostController (для страницы с новостями), PhotoController (для страницы с галереями).
Еще нужен контроллер для страниц логина/регистрации/забыл пароль — UserController, AuthController или что-то такое.
> Если вздумается на одной странице делать и вывод новостей, и галерею фото, то делаем один контроллер. Хз как его тогда назвать, какой-нибудь PostAndPhotoController,
Можно обозвать фото и новости постами и сделать PostController. Или ContentController.
> Нужно ли создавать тогда отдельный контроллер для комментариев
дело вкуса. Можно не создавать.
> что контроллер для комментариев есть смысл делать только ради админки, где у нас будет возможность их редактирования/удаления?
Обычно контроллеры админки отделены от контроллеров сайта, так проще безопасность обеспечивать, хотя в Yii это может быть и не так. не знаю.
> Делать StatisticController, который будет использовать все необходимые модели?
да
> Там проще Spylog или HotLog поставить.
В наше время используют Google Analytics и яндекс метрику.
>>487603
Так себе, после нее доучиваться придется. Книга старая, код так себе, для ознакомления может быть сгодится.
Если что у нас в ОП посте есть задания по всем этим JS/HTML/CSS/SQL и они помогут тебе определить научился ли ты чему-то или нет и где у тебя пробелы в знаниях.
>>487637
> накидай пожалуйста каких-нибудь ссылок по паттернам
Паттерны нет смысла изучать если ты не видел код который их использует. То есть сначала код, потом паттерны, не наоборот.
А так, культовая книга по паттернам это Фаулер, Паттерны (шаблоны) проектироания корпоративных приложений. Он в этой книге описал и разложил по полочкам подходы к решению задач которые он видел в том коде с которым сталкивался.
Вот сам список: http://martinfowler.com/eaaCatalog/
Вот русский частичный перевод: http://design-pattern.ru/
Можешь туда поглядывать, может какой знакомый паттерн увидишь.
Паттерны хороши тем, что позволяют программистам проще объяснить друг другу свою идею: «а давай тут Data Mapper использовать, а не ActiveRecord». Ну и позволяют не изобретать велосипед, а выбрать готовый вариант решения.
Ну вот кстати паттерн, с которым ты должен быть знаком — ActiveRecord. Это когда модель умеет сама себя сохранять и загружать из базы. У меня есть урок на эту тему. если бы ты делал наши задачки, тебе бы пришлось его прочесть обязательно, а так можешь прочесть добровольно: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
> Там проще Spylog или HotLog поставить.
В наше время используют Google Analytics и яндекс метрику.
>>487603
Так себе, после нее доучиваться придется. Книга старая, код так себе, для ознакомления может быть сгодится.
Если что у нас в ОП посте есть задания по всем этим JS/HTML/CSS/SQL и они помогут тебе определить научился ли ты чему-то или нет и где у тебя пробелы в знаниях.
>>487637
> накидай пожалуйста каких-нибудь ссылок по паттернам
Паттерны нет смысла изучать если ты не видел код который их использует. То есть сначала код, потом паттерны, не наоборот.
А так, культовая книга по паттернам это Фаулер, Паттерны (шаблоны) проектироания корпоративных приложений. Он в этой книге описал и разложил по полочкам подходы к решению задач которые он видел в том коде с которым сталкивался.
Вот сам список: http://martinfowler.com/eaaCatalog/
Вот русский частичный перевод: http://design-pattern.ru/
Можешь туда поглядывать, может какой знакомый паттерн увидишь.
Паттерны хороши тем, что позволяют программистам проще объяснить друг другу свою идею: «а давай тут Data Mapper использовать, а не ActiveRecord». Ну и позволяют не изобретать велосипед, а выбрать готовый вариант решения.
Ну вот кстати паттерн, с которым ты должен быть знаком — ActiveRecord. Это когда модель умеет сама себя сохранять и загружать из базы. У меня есть урок на эту тему. если бы ты делал наши задачки, тебе бы пришлось его прочесть обязательно, а так можешь прочесть добровольно: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Фаулера мне >рановато читать >>485186
ActiveRecord знаю.
Просто хочу быть готовым к "само собой разумеющимся" моментам, которые опускаются в мануалах и документациях.
>если бы ты делал наши задачки
Да я уж половину ваших (ты там не один, штоле?) задач перерешал.
Задание про студентов делал, правда не доделал до конца.
Сейчас хочу сделать файлообменник. На голом php не хочу делать, пора браться за фреймворки.
Буду делать на yii, но для этого нужно его изучить. Кроме того, там оказывается еще куча расширений, их тоже надо знать. А то я например начну писать свой велосипед для галереи картинок, а окажется, что такое расширение уже есть.
Поэтому я сейчас занят чтением мануала и api. Не начну делать большое задание, пока при помощи хелловорлдов не изучу все возможности фреймворка.
Не в рашке служил
>Итератор используется когда ты пытаешься применить цикл foreach к объекту
Используется, но не поэтому. Идея - заменить структуру данных алгоритмом перебора. Т.е., например, у тебя есть триллион объектов, и их надо перебрать. Ты их не выбираешь в массив все сразу (чтобы не засирать всю память), а держишь лишь один объект (сам итератор) и берешь по одному.
Стандартные итераторы PHP должны имплементировать потомков интерфейса Traversable:
http://php.net/manual/ru/class.traversable.php
И да, foreach() в PHP зачастую является циклом выбора: работает быстро, и вообще заебат. Часто, использование "break" или "continue" в нем предпочтительней, чем использование других циклов (хотя общая практика высокоуровнего программирования не рекомендует подобные конструции).
При помощи итератора можно сделать многое. Из очевидного на ум приходит, например, обход дерева файлов и каталогов, или перебор записей в таблице. Так что юзайте их, нахуй.
Вот, как по мне, удобный сервис, для проверки в разных версиях PHP:
http://sandbox.onlinephpfunctions.com
Кастрированный малость, но сойдет.
>Анон, подскажи можно ли так делать?
Делать-то можно, только синтаксис совсем кривой:
- отступы совсем ни к черту
- "return" лучше иметь единственный; в конце функции/метода
- нет пробела между "if" и открывающей скобкой
- нет пробелов перед и после оператора "меньше"
- "return" ничего не возвращает. Это допустимо (будет возвращен null), но считается плохим стилем
Нужно что-то просто, вроде фреймворка Slim, но с авторизацией, структурой базы данных, админкой?.
Самому писать это оче лениво и долго, а мне нужно сделать задачу быстро.
А зачем тут else? Пиши просто
if ($a < $b) {
return;
}
//a lot of code
Смотри насколько проще и читабельнее стало.
>>487880
> "return" ничего не возвращает. Это допустимо (будет возвращен null), но считается плохим стилем
Это нормально если функция ничего не возвращает, и return используется для выхода из нее. Ну например:
function notifyUser(User $user = null)
{
if (!$user) {
return;
}
$this->someService->sendNotification($user->getId(), SOME_CONSTANT);
}
А зачем тут else? Пиши просто
if ($a < $b) {
return;
}
//a lot of code
Смотри насколько проще и читабельнее стало.
>>487880
> "return" ничего не возвращает. Это допустимо (будет возвращен null), но считается плохим стилем
Это нормально если функция ничего не возвращает, и return используется для выхода из нее. Ну например:
function notifyUser(User $user = null)
{
if (!$user) {
return;
}
$this->someService->sendNotification($user->getId(), SOME_CONSTANT);
}
Эти все md5, sha1, crypt и т.д. Принцип работы этих алгоритмов, сравнение, безопасность и т.д.
<style type="text/css">
#status {
height: 200px;
width: 50%;
margin: auto;
background: #000000;
}
</style>
<body>
<div id="status">
</div>
</div>
</body>
<script>
var stat = document.getElementById('status');
stat.style.offsetHeight=500 + "px";
document.write(stat.offsetHeight);
</script>
То есть пытаюсь присвоить диву номер размер, а он не присваивается, в чём дело? Что тут неправильно?
offsetHeight только на чтение.
Что ты вообще пытаешься сделать? Изменить высоту? Почему тогда не использовать обычный height
>А зачем тут else?
Потому что в глобальном потоке, а не в функции.
Этот файл инклудится. Как себя поведет скрипт если написать как ты? Документация говорит что выполнится "a lot of code"
Тебе надо менять стиль height, через node.style.height = '500px';
Но я бы советовал остановиться тут и подумать, как реализовать то, что тебе нужно, через CSS. Использовать JS для стилей это костыль, который может плохо работать, из-за которого твой сайт скорее всего будет дергаться и прыгать ии может быть плохо отображаться на мобильных устройствах или где-то еще.
>Но return вообще-то позволяет выйти из подключенного файла
Позволяет, но есть 2 момента:
1) есть много куда более удобных способов
2) $x = require_once 'blah-blah-blah'; выглядит настолько убого, что пиздец
Не уверен, возможно что и нет. Но я знаю что огромные блоки в if/else, тем более когда без них легко обойтись, это нечитабельно и я не понимаю какое вообще отношение к этому имеют блок-схемы.
Там return исплоьзуется не для возврата значения а для выхода из файла, перечитай посты.
> есть много куда более удобных способо
перечисли
>Но я знаю что огромные блоки в if/else, тем более когда без них легко обойтись
Ты из тех, кто пишет так?
if (0 < $x) return;
if (3 > $y) return;
// Code
Я скобки ставлю фигурные вокруг return, но да, пишу так. Потому что код получается линейный и без лишних вложенностей. И да, так читабельнее, чем менбше отступов тем проще читать.
>>488240
Это же отстойно, если у тебя например все тело функции засунуто в if, ты просто добавляешь отступ и снижаешь читабельность.
Ну представь простой пример: функция которая что-то делает. И есть 4 условия при которых делать ничего не надо, а надо допустим вернуть какой-то код. Для определения истинности каждого условия надо написать 2-3 строчки кода. Как ты это запишешь?
Алсо обрати внимание на второй пост треда:
> не проповедуй
всякие альтернативные и маргинальные точки зрения (вроде использования табов вместо пробелов или отступлений от стандартов PSR) тут не приветствуются.
Проповедовать здесь можно только тебе?
Почему быдлокод? И ты не написал как по твоему решить ситуацию с несколькими выходами из функции.
Со вчера ошибка, не гуглиться, точнее гуглиться, но не то.
Ошибка.
Кофнфиг модуля
http://ideone.com/bzvMAe
Ты и с одним не написал. И кстати свое мнение никак ни обосновал и не подкрепил ссылками на стардарты, так что будем считать тебя троллем.
>>488319
> parseRouteDefinition('/album[:/action...')
Видно что проблема при попытке распарсить этот роут. Он точно соответствует синтаксису зенда?
Алсо ты можешь открыть файл C:\xampp\htdocs\install\vendor\zendframework\zendframework\library\Zend\Mvc\Router\Http\Segment.php:175 и посмотреть что именно там не так. Ты также можешь туда поставить например var-dump который выведет значения разных переменных.
Я как-то не думал лезть в код фреймворка, полез, таки нашел, я : не там поставил. На 175 парситься код роутера.
Код — лучшая документация! Привыкай (как альтернатива, можно отладчиком точку останова ставить, это даже удобнее, но нужна IDE).
Спасибо. Очень удобно на самом деле.
Я пока не хочу устанавливать IDE. Надо в униве экзамен на delphi, а когда сдам, тогда уже установлю линуху с ide какой-нибудь, посмотрю, какую на работе используют. Наверное на этой недели выхожу, я тот анон, который архиватор делал.
Вот у меня есть таблица со столбцами id, name, которые формируют первичный ключ (это было сделано для сохранения уникальности столбца name, хотя теперь я уже знаю, что лучше было повесить на него отдельный индекс UNIQUE).
Так вот, как мне теперь переопределить первичный ключ? ALTER TABLE tblname DROP PRIMARY KEY выдает ошибку
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
Ну я сейчас сделаю дамп и руками исправлю определение таблицы, перед тем как залить базу обратно. Но хотелось бы знать, как все-таки сделать правильно.
Да, я что-то не подумал, что можно перечислить две инструкции через запятую.
Отдельно ключ не удалялся наверное потому что на него ссылается внешний.
Так работает, спс.
Доброняш, прохикковал осень-зиму-весну в бодишопе ололо-вордпрессдевом, понял что деградирую, решил сваливать.
Можешь накидать вопросов на стронг-джуна или слабого мидла? Где-то в прошлых тредах видел, но не скопировал себе.
С меня лучи добра.
Коммерческого ничего особого. Ну доработки только на Yii и плюс Мажента с её богомерзким ZF. Печаль-тоска.
Ну ты богомерзким именно ZF назвал. А маджента не знаю, я только на следующей недели выхожу и работать с ней только предстоит, ну а вообще не думаю, что хуже ВП что-то есть
>плюс Мажента с её богомерзким ZF. Печаль-тоска.
С такими-то глазами, братюнь, удачи тебе в освоении милашественной Magento, лол.
Я з ZF назвал милашеством, он мне мою божественную Django напоминает
Я из того, что очень популярно на западе. Меня crm от битрикса заставили пользываться. И один раз правил такую хуёту как hostcms, загугли - поплачешь
<div id="klick">
<p id="b1" onclick="foo(this)">Клик 1</p>
<p id="b2" onclick="foo(this)">Клик 2</p>
<p id="b3" onclick="foo(this)">Клик 3</p>
</div>
<script>
function foo(el) {
document.write(el);
}
</script>
При клике выводит вот это:
[object HTMLParagraphElement]
Где можно найти свойства этого объекта? Как можно вывести сам хтмл код или его текст?
>onclick="foo(this)"
За такое нужно отрубать руки.
А теперь попробуй сходить сюда, няш http://www.w3schools.com/jsref/met_element_getattribute.asp
Энтрилевел это Ubuntu/Mint же. Потом сможешь перейти на что-нибудь другое, если желание возникнет. Хотя я ставил Линукс и мне не понравилось совершенно, какое-то все вырвиглазное, глаза устают от шрифтов и подбора цветов. Сразу видно, что любители делали.
неОП
>Хотя я ставил Линукс и мне не понравилось совершенно, какое-то все вырвиглазное, глаза устают от шрифтов и подбора цветов
высер типичного пхпшника
PHP и Windows стали популярны, потому что они просты и функциональны, т.е. с легкостью выполняют свои задачи. Linux же вне серверов не нужен, т.к. предъявляет определенные требования к пользователю, при этом не предоставляя практически никаких преимуществ. А то немногое, что все-таки есть не перекрывает его минусов.
Ну и плюс у каждого второго школьника свое видение идеальной ОСи и поэтому они распыляются на тысячи бесполезных говнодистрибутитов вместо того, чтобы сконцентрировать все свои силы на одном или на крайний случай на паре-тройке.
>требования к пользователю
iq > 60 ?
>windows с легкостью выполняет свои задачи
wordpress с легкостью выполняет свои задачи, нахуй учить php, это гамно для задротов
Покормил.
>iq > 60 ?
Нет, нужно понимание того, как работает Linux. Конечно в Ubuntu/Mint это в гораздо меньшей степени выражено, но все равно они не такие юзер френдли, как тот же Windows.
>wordpress с легкостью выполняет свои задачи
Таки да, если тебе нужно небольшой бложик с низкой посещаемостью, то wordpress идеально подходит. Если же нужно нечто большее, то желательно поискать другие варианты.
Ты че охуел, а ну вежливым будь и поясни мне за профиты перед убунтой.
Больше заточен под сервер.
Тебе пока не нужно знать тонкости, главное работа в командной строке, она почти везде одинакова.
Суть в том, что на рабочих серверах нет графического интерфейса.
Так что все что тебе пока надо знать - это как скопировать файлики (ctrl+c не работает, мыши тоже нет), или изменить права доступа.
>юзер френдли
Хер знает, что под этим подразумевают.
Как по мне, гораздо удобнее написать в командной строке apt-get remove, чем искать в этих гребаных менюшках "Удаление программ".
До сих пор боюсь ставить восьмерку. Мало ли что они там намутили с этими меню, вкладками и прочей ерундой.
Да ты ретроград, как я посмотрю. Впрочем, восьмерка мне тоже не понравилась, именно поэтому и решил потестить Линукс. Но в итоге все равно поставил божественную семерку, хоть и пришлось попердолиться с UEFI.
На самом деле я уже сижу на убунте, права и копирование освоил, только сама убунта толком не работает на моем ноуте, уже с неделю мучаюсь. Почитал про CentOS, понравилось.
Скажите мне только одно. Если я поставлю сейчас этот центос, я смогу наконец-то начать работать над сайтиками, а не пердолиться чтоб оно заработало?
>убунта толком не работает на моем ноуте
Что именно не работает?
>Почитал про CentOS, понравилось.
Читал официальные форумы, или треды илитариев с бе?
>Если я поставлю сейчас этот центос, я смогу наконец-то начать работать над сайтиками, а не пердолиться чтоб оно заработало?
Нет, не сможешь. Centos для опытных разработчиков. Установив centos, ты не станешь опытным разработчиком.
>Что именно не работает?
Периодически хром (как страница, так и сам хром) бьется на пиксели и полосы, при скроле, да и просто так, все это весело мигает и переливается пикселями. Иногда спасает свертывание\развертывание, иногда только перезапуск хрома, а иногда такая хуйня начинается и в системе. Бесит неимоверно. Драйвера\флеш крутил-вертел пару дней, не починил.
>Читал официальные форумы, или треды илитариев с бе?
Читнул официальный фак, возбудился от слов вроде энтерпрайз, редхат
>Centos для опытных разработчиков.
Спасибо что избавил от мучений.
Может дело в железе? Походу у тебя видеокарта перегревается, или материнская плата.
Не знаю, у меня вообще слабый ноутбук, на нем восьмерка наверное даже не запустится.
На xubuntu Morrowind летает на средних настройках.
Centos (или что угодно другое) можешь поставить на виртуальную машину, если так интересно.
Если у тебя xubuntu работает нормально, то и восьмерка пойдет. У меня она в дуалбуте, а ноут на самом деле нетбук, мощностями естественно не выделяется. Но восьмерка вполне пристойно работала, пока активации не потребовала, сучара.
>или что угодно другое
Дебиан уже скачался, прощайте посоны.
Пиши console.log(el) после чего открой консоль в браузере (Ctrl + Shift + J) и смотри там во всех подробностях.
Хром выводит иногда HTML-верстку вместо объекта. в таком случае попробуй console.dir(el)
Ну и меняй свой старый учебник яваскрипта на learn.javascript.ru, это по моему лучшее что есть на русском.
>>488734
Ubuntu или Debian. Debian минималистичнее и чуть суровее но в общем тоже довольно дружелюбный и очень надежный.
Я на винде + линукс в виртуалбоксе.
>>488737
> >onclick="foo(this)"
> За такое нужно отрубать руки.
Ты читал пост >>487140 ? Аргументируй, тем более что я с тобой не согласен, инлайн-обработчики имеют немало преимуществ:
— работают с момента появления элемента на экране (а не с момента загрузки страницы/срабатывания document ready который может сработать неизвестно когда)
— сразу видно что вызовется при клике
Вообще по моему инлайн обработчики для простых случаев как раз самый лучший способ.
> Периодически хром (как страница, так и сам хром) бьется на пиксели и полосы, при скроле, да и просто так, все это весело мигает и переливается
Либо кривая версия Хрома (попробуй фаерфокс например) либо что более вероятно, в линуксе опять сломали графическую подсистему — а сломана она по моим сбъективным ощущениям, постоянно. Ну или драйвера у тебя кривые или устарели в сравнении например с версией иксов. Попробуй поменять проприетарные на открытые или наоборт если есть возможность. Приготовься что при этом после перезагрузки скорее всего графическая оболочка отвалится полностью, в этом случае грузись в safe mode и через командную строку все чини. Ну и заранее почитай что делать в таких случаях.
>>488915
Странно, под виндой у анона все работает, а под линуксом нет? Ну вообще конечно можно как вариант выключить графическое ускорение и какой-нибудь XFCE поставить.
Понятно что профит в этом, но вопрос другой. Чем одно от другово отличается? Я бы понял что быстрее или проще, но в итоге вроде как тоже самое получилось.
$STH = $DBH->query('SELECT hui, pizfa, jigurda from dvach');
$STH->setFetchMode(PDO::FETCH_OBJ);
while($row = $STH->fetch()) {
echo $row->hui. "\n";
echo $row->pizfa. "\n";
echo $row->jigurda . "\n";
}
Как поменять кодировку вывода из мускула на UTF8?
Я понимаю что нужно
mysqli_set_charset($link, "utf8")
Но как сделать это с PDO?
А, понял.
$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$DBH->exec("set names utf8");
ОП пост читал? Мэтт Зандстра и Шлосснейгл неплохие, хотя и не очень новые. Также, хорошие книги (хотя некоторые из них не для начинающих):
Макконелл «Совершенный код»
>>488976
Да различия так не очень большие, но PDO умеет выбрасывать исключения при ошибке ,а mysqli например нет.
>>488977
Что сложного в числах Фибоначчи? Там же только сложнение используется. Ну и на собеседовании могут попросить посчитать их, тут-то тебе это и пригодится.
>>489002
Лучше указывать параметр charset при создании объекта PDO: http://php.net/manual/ru/ref.pdo-mysql.connection.php (англ)
Простую доску объявлений с категориями без регистрации, потом допиливай, добавляй WYSIWYG-реддактор (не забыдь фильровать HTML), прикрепление картинок и файлов (не разрешай загружать всякие левые файлы), поиск, поддержку нескольких городов и языков, VIP аккаунты, оплату, личный кабинет.
>Что сложного в числах Фибоначчи?
Дело не в сложности, а в полезности знаний. Новичка нужно учить базовым понятиям и функциям, которые чаще всего используются, а не заставлять решать бесполезные задачки, которые скорее всего никогда не пригодятся. А даже если и пригодятся, то можно просто загугить решение. Зачем пичкать голову мусором, если туда нужно помещать полезные знания?
О, нет досок объялвений я напилялся будучи школьником с функциональным кодом, ты мне дела идею, лучше уж сервис заметок, по-сути, та же доска, но другое
Подучивай: фреймворки (хотябы Yii1/2 надо знать, хорошо бы еще зенд полноценно изучить или симфони).
По базам данных: внешние ключи, нормализация, транзакции, индексы, также посмотри задачи по MySQL из ОП-поста.
По JS тоже неплохо бы пару библиотек каких-нибудь освоить, DOM, jQUery это само собой, а вдобавок например jQuery UI какой-нибудь.
Отладчиком в IDE научись пользоваться. Git само собой.
Насчет вопросов, смотри задачи по MySQL и вот тут есть какие-то задачи с собеседований: https://github.com/codedokode/pasta/blob/master/interview-tasks.md
PhpStorm
Netbeans (говорят он старенький и не очень)
Eclipse PDT
Zend Studio
Есть также сторонние отладчики: http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=php+debugger+gui
Алсо у меня была мысль одно время попробовать написать (силами анонов-добровольцев) свой отдельный отладчик, но что-то я пока не уверен что найдутся желающие и что надо делать именно отдельное приложение, а не например плагин к какому-нибудь саблайму. Тем более что для саблайма уже есть клиент и правильнее наверно допиливать его, а не писать свой: http://www.sitepoint.com/debugging-xdebug-sublime-text-3/
https://roem.ru/01-06-2015/196600/1c-zahvatil-it/
Любители других языков в очередной раз остались с тарелкой борща, это просто праздник какой-то.
>>Fatal error: Class 'SQLite3' not found
Пробую PDO, так оно мне
>>could not find driver
Нужные библиотеки в php.ini раскомментированы...
WTF?
Я открываю официальный сайт https://facebook.github.io/react/ в надежде на главной странице увидеть объяснение, что это такое.Вроде «React is a JS library that...». Разумеется объяснения нет (только короткая строчка A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES), вместо этого сразу идет примеры без разъяснения терминов:
> React (что это?) components (что это?) implement a render() method that takes input data
Причем глянув на код мы видим:
— в библиотеке идет свой велосипед для реализации классов, вместо использования любой сторонней библиотеки по моему желанию
— мы пишем HTML разметку прямо в JS коде
Разметка в коде! И это подается как новая технология, хотя это мы все уже видели в PHP 15 лет назад и в E4X который так и не взлетел.
Бонусом мы получаем отстутствие подсветки, анализа кода и т.д.
— массиво-ориентированное программироание:
> this.setState({secondsElapsed: this.state.secondsElapsed + 1});
Что за ерунда? Почему я должен использовать какой-то странный setState вместо нормальных свойств или моделей или вызова setSecondsElapsed? Почему я не могу задать их значения нормально в конструкторе, а не в непонятном методе getInitialState?
Ну и примеры кода на главной странице ничего не говорят и не объясняют. Я например не понимаю какая выгода использовать реакт когда то же самое (что делается в примерах) делается 2 строчками на jQuery (то есть я понимаю что выгода может и есть, но из объяснений это не видно).
Они говорят что у них есть какой-то Virtual DOM и можно рендерить страницы на сервере, но почему на главной про это не слова? Разве то не главная особенность библиотеки? И если они рендерят страницы то почему таким ненормальным способом, а не через шаблонизатор?
В общем у меня ощущение что это какая-то штука нужная в первую очередь фейсбуку для специфических задач на своих проектах и которую другие пытаются засунуть везде где можно лишь бы использовать.
Причем они там сделали новый синтаксис, JSX. Этот язык можно компилировать прямо в браузере (просто) и на сервере (сложно). Давайте-ка угадаем, какой подход выберет среднестатистический неуч-верстальщик?
Я не то что бы против новых вещей, но конкретно эта библиотека выглядит как-то сомнительно.
Я открываю официальный сайт https://facebook.github.io/react/ в надежде на главной странице увидеть объяснение, что это такое.Вроде «React is a JS library that...». Разумеется объяснения нет (только короткая строчка A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES), вместо этого сразу идет примеры без разъяснения терминов:
> React (что это?) components (что это?) implement a render() method that takes input data
Причем глянув на код мы видим:
— в библиотеке идет свой велосипед для реализации классов, вместо использования любой сторонней библиотеки по моему желанию
— мы пишем HTML разметку прямо в JS коде
Разметка в коде! И это подается как новая технология, хотя это мы все уже видели в PHP 15 лет назад и в E4X который так и не взлетел.
Бонусом мы получаем отстутствие подсветки, анализа кода и т.д.
— массиво-ориентированное программироание:
> this.setState({secondsElapsed: this.state.secondsElapsed + 1});
Что за ерунда? Почему я должен использовать какой-то странный setState вместо нормальных свойств или моделей или вызова setSecondsElapsed? Почему я не могу задать их значения нормально в конструкторе, а не в непонятном методе getInitialState?
Ну и примеры кода на главной странице ничего не говорят и не объясняют. Я например не понимаю какая выгода использовать реакт когда то же самое (что делается в примерах) делается 2 строчками на jQuery (то есть я понимаю что выгода может и есть, но из объяснений это не видно).
Они говорят что у них есть какой-то Virtual DOM и можно рендерить страницы на сервере, но почему на главной про это не слова? Разве то не главная особенность библиотеки? И если они рендерят страницы то почему таким ненормальным способом, а не через шаблонизатор?
В общем у меня ощущение что это какая-то штука нужная в первую очередь фейсбуку для специфических задач на своих проектах и которую другие пытаются засунуть везде где можно лишь бы использовать.
Причем они там сделали новый синтаксис, JSX. Этот язык можно компилировать прямо в браузере (просто) и на сервере (сложно). Давайте-ка угадаем, какой подход выберет среднестатистический неуч-верстальщик?
Я не то что бы против новых вещей, но конкретно эта библиотека выглядит как-то сомнительно.
Апач перезапускал?
Алсо, сделай файл с кодом <?php phpinfo(); открой его через браузер и посмотри есть ли там PDO и драйвер PDO для sqlite.
О, по ссылкам можно найти хорошую статью которая должна быть на главной странице и которая объясняет идею авторов: https://facebook.github.io/react/docs/thinking-in-react.html
Если сравнить с ангуларом то по моему тот удобнее: он позволяет тебе сделать таблицу таблицей в шаблоне. а не превращать ее в смесь разметки и JS кода.
Очевидно что нужны библиотеки для View, нужен data-binding, но почему-то то что есть в open source неадекватно и пишется какими-то аутистами:
— react размешивает разметку по коду, неюзабелен абсолютно
— angular вместо того что бы предложить просто хорошие шаблоны с data binding городит какую-то систему своих классов, тегов, компонент, роутер, сервисы и пытается все это впарить в довесок. Плюс говорят там поис кизменений неэффективный, плюс чтобы разбить код на модули надо танцевать с бубном
— knockout не впаривает ничего лишнего, но синтаксис относительно тяжелочитаем и тяжело пишется
Ну выбирать тут если и можно то по принципу «меньшее из зол». И для каждой библиотеки найдется куча человек которые ее нахваливают, и никто не критикует. Как так?
Почему нельзя делать маленькие библиотеки делающие хорошо одну вещь, а не плохо, но все сразу?
Вот тут хорошо упоминается ангулар: http://www.arturdr.ru/web/tolko-react-js-tolko-hardkor-aka-doloy-angular-i-knockout/
> Стэковерфлоу переполнен ответами на тему angular vs. performance, и лучше всего ситуацию проиллюстрируют два ответа: детальнейшее описание работы dirty-checking в Angular, сводящееся к тому, что если на странице у вас меньше 2000 элементов, то всё будет отлично (а уж 2000 элементов должно быть достаточно для каждого!). И следующий за ним контрпример, что в случае больших таблиц 2000 элементов набегают очень быстро.
В нашем случае у нас было много выпадающих списков, вроде таких: с большим количеством выпадающих элементов, значения которых были привязаны к модели. Заветные 2К элементов набежали очень быстро, и при изменении модели всё нереально тормозило (двух-трехсекундный лаг в браузере нельзя было не заметить).
Я не понимаю как после этого его вообще кто-то еще ипользует. Или у них так медленно работает мозг что задержек они не видят?
Видимо JS так прост в изучении, что мир заполонила толпа недоучек-изобретателей велосипедов которые пиарят свои велосипеды.
Что меня обнадеживает, так это то что во многих вакансиях требуют не знание новомодных слов и умение скачать yeoman с гитхаба, а написание кода на vanilla js и знание алгоритмов. думаю, это хороший способ отсеивать тех, кто умеет только «программировать на jqeury».
Не говори за всех.
http://angularlight.org/doc/advantages.html
> There no objects like: constant, value, factory, service, provider, application, module (from Angular.js), you have more freedom
Но мне кажется для решения проблем производительности надо просто сделать на выбор несколько вариантов поиска изменений, и разработчик может выбрать тот который лучше работает в его прилжениее:
— dirty-check как в ангуларе, минимум усилий, минимум производительности
— Object/Array.observer там, где он поддерживается, при определенных условиях это может дать хорошую производительность (но как я понимю далеок не всегда)
— явное сообщение об изменениях в модели — для сложных случаев
Например в той же ORM Doctrine такой выбор есть: ты можешь выбирать, какими способом она будет искать изменения в моделях. Почему бы JS-молодежи не поучиться у опытных PHP- и Ява-дядек, которые написали кучу кода и успели наступить на все возможные грабли?
Винда? Откуда PHP качал? Лучше скачать официальную версию с нужными модулями, а те которых там нет скачать руками, положить в папку ext например и прописать в php.ini их зазрузку
Мануал http://php.net/manual/ru/install.windows.extensions.php
http://php.net/manual/ru/install.pecl.windows.php
Это нормально. Устанавливаешь только то что тебе нужно пакетным менеджером. В дебиане это apt-get install и даже в конфигах править ничего не надо.
Код работает. Просто регулярка неправильная. Мне щас лень объяснять, да и я не силён в них, ОП придет пояснит.
Ну да, я про регулярку и говорю. Не понимаю что не правильно, вроде все 10 раз перепроверил, должно работать.
Учи синтаксис регулярных выражений. Какой смысл в том, что кто-то напишет тебе решение.
Например, зачем ты взял восьмерку в скобки?
\\s - что это? Зачем два слеша?
>Например, зачем ты взял восьмерку в скобки?
Привязка к началу строки.
>\\s - что это? Зачем два слеша?
Экранирование символа.
Преобразовывать номер нельзя? Типа хоть пробелы (если есть) убрать?
Паттерн нужно упростить, в любом случае. И "[0-9]" == "\d".
39999+7777 в последнем.
я посмотрел, вроде клевые вещи, делают верстку лаконичнее читабельнее и проще.
Что думаешь про twitter bootstrap, стоит ли использовать?
Хочется сократить трату времени на верстку и больше внимания уделять бэкенду. Может ты еще подскажешь что?
Ты можешь отлаживать регулярки на сайте https://regex101.com/
ТОлько там надо обратный слеш писать один раз, а не два, то есть \s а не \\s
Вот твоя регулярка: https://regex101.com/r/lM3sA5/1
Как мы видим там идет в конце:
[0-9]{3}[\s-]{0,3}[0-9]{2}[\s-]{0,3}([0-9]{2})
То есть она ищет такой номер:
3 цифры - 2 цифры - 2 цифры
А у тебя в номере другое распределение цифр.
Ну и твою задачу надо проверить на других номерах.
Задачу про номера телефонов надо проверить на большом числе телефонов, чтобы убедиться что твой код правильный. Но руками подставлять номера — долго и скучно. Пусть работает робот, а не человек!
Для этого давай добавим в программу тесты, чтобы сразу было видно, верно все работает или нет. Сделай 2 списка номеров (правильные и нет), добавь их в программу и напиши цикл, который их по очереди прогоняет через регулярку и проверяет что они определяются как надо (если нет — надо вывести какой именно номер не распознается правильно).
Вот список номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
Ты можешь отлаживать регулярки на сайте https://regex101.com/
ТОлько там надо обратный слеш писать один раз, а не два, то есть \s а не \\s
Вот твоя регулярка: https://regex101.com/r/lM3sA5/1
Как мы видим там идет в конце:
[0-9]{3}[\s-]{0,3}[0-9]{2}[\s-]{0,3}([0-9]{2})
То есть она ищет такой номер:
3 цифры - 2 цифры - 2 цифры
А у тебя в номере другое распределение цифр.
Ну и твою задачу надо проверить на других номерах.
Задачу про номера телефонов надо проверить на большом числе телефонов, чтобы убедиться что твой код правильный. Но руками подставлять номера — долго и скучно. Пусть работает робот, а не человек!
Для этого давай добавим в программу тесты, чтобы сразу было видно, верно все работает или нет. Сделай 2 списка номеров (правильные и нет), добавь их в программу и напиши цикл, который их по очереди прогоняет через регулярку и проверяет что они определяются как надо (если нет — надо вывести какой именно номер не распознается правильно).
Вот список номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
Bootstrap это вообще маст хэв. Всякие дополнительные плюшки можешь и не использовать конечно, но сетка у них божественная. Адаптивный дизайн проще простого пилить.
не ОП
>>Например, зачем ты взял восьмерку в скобки?
> Привязка к началу строки.
Привязка это символ ^. Скобки тут ничего не делают.
>>489350
> \\s - что это? Зачем два слеша?
Строка обрабатывается по правилам PHP который заменяет 2 слеша на один и передает этот один слеш движку регулярок. \s тоже можно писать, но на некоторых сочетаниях будут проблемы. Например чтобы найти бекслеш ты должен передать движку регулярок \\ но чтобы вписать это в строку надо удвоить каждый бекслеш и писать \\\\.
Мануал http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
>Привязка это символ ^. Скобки тут ничего не делают.
А разве в таком случае привязка не будет относиться ко всему выражению?
Можно но проще же одну регулярку написать.
>>489364
Запости на ideone или аналогичный сервис, как мы не имея возможности запустить твой код. его проврим?
7777 надо прибавлять в самом начале а не к итоговой сумме.
>>489367
Да. Они повышают читабельность и удобство написания. Также teig экранирует данные с помощью htmlspecialchars что защищает от XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
Twig кстати это клон питоновского jinja потому там не используют доллары перед переменными.
> Что думаешь про twitter bootstrap, стоит ли использовать?
Для админки или личного кабинета подойдет и скорее всего он будет красивее того что ты сделаешь сам (если ты не дизайнер). для сайта наверно не нужно так как дизайн рисует дизайнер и надо верстать его, а бутстрап скорее будет плаки в колеса ставить. Да и бустрап настолько часто использован что если мне например уже надоело на него смотреть.
> Хочется сократить трату времени на верстку
Иди в компанию где есть верстальщики. Если у программиста маленькая зарплата то нанимать верстальщика незачем, а если высокая то оправданно.
чет протупил, там условие в фор через запятые поставил
for ($month = 0; $month <= 20; $month++) fixed
Приелся, я уже эти синие кнопки и ариал 14 размера видеть не могу.
> Адаптивный дизайн проще простого пилить.
Что там такого есть? По моему @media написать можно и без бутстрапа. Да и как я понимаю, автор вопроса не верстальщик и на адптивность ему врмя тратить неохота. Часто и неадаптивная старница вполне сойдет если она правильно и резиново сверстана.
> но сетка у них божественная
Что божественного? Обычная сетка из 12 колонок.
Я понимаю, но sqlite3 то почему отдельно? Казалось бы по дефолту вместе идти должны, ан нет.
Потому что PHP заменяет 2 бекслеша на один при разборе строки и движок регулярок получает 1 бекслеш: http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
>>489374
Она не может относиться ко всему выражению. Символ ^ значит только то, что слева от него должно быть начало строки, и перед ним нет ни одного символа. Соответственно ставь или не ставь скобки — ничего не меняется.
Скобки нужны в другой ситуации, совместно с «или»:
^abc|def
(^abc)|(def)
Или abc в начале строки или def в любом месте
^(abc|def)
abc или def в начале строки.
Потому что к PDO идут драйвера для многих баз данных и ты можешь не хотеть какие-то устанавливать. Они сделаны отдельными расширениями, pdo_mysql, pdo_sqlite и тд. Сам по себе PDO без драйверов бесполезен.
>Можно но проще же одну регулярку написать.
Дефис и/или пробел могут быть перед любым символом, и даже по несколько штук. Вот такая хрень положит тебе номер в $matches[1] в стандартизированном (например, для базы данных) формате:
preg_match('/8(\d{10})/S', preg_replace('/[-\s]+/S', '', $number), $matches);
Анон зацени: http://ideone.com/xUBlw2
Сделал так, чтобы сначала выкидывало все говно типа пробелов, скобок, тире, потом уже сравнивало с простенькой регуляркой. Вроде работает. Сначала идут правельные номера, потом неправильные.
Это лучше писать в несколько строк, но я понял твою идею. Там в первой части задачи надо только проверить номер на правильность. а во второй нормализовать. Можно вырезать пробелы, но регуляркой решить задачу будет чуть интереснее.
>>489404
> for ($i = 0; $i < count($right); $i++) {
для перебора массива лучше подходит foreach, думаю надо поменять
> \t$parts = preg_split($reg, $right[$i], 0, PREG_SPLIT_NO_EMPTY);
> $right[$i] = "";
> for ($j = 0; $j < count($parts); $j++) {
Для замены есть функция preg_replace (она описана ниже в уроке), лучше написать ее, а не делать сложный цикл, который трудно прочесть и в котором легко сделат ошибку.
Вывыодить данные (номер и правильный ли он) лучше не раздельно, а вместе, а то неудобно проверять.
Или же скиньте ссылочку где все это расписано ясно и понятно.
Я уже заебался ребят. Пришел сюда, к Вам
В одном из курсов специалист есть задание сделать капчу, с решением конечно же. Только не помню в каком.
Линуксоиды-программисты довольно мерзкие и двуличные люди. Когда они верстают сайт, то они его верстают так, что в Ие он не работает, они ставят https сертификат который не поддерживается в Windows XP, на смартфонах что-нибудь не кликается. Более того, они еще и ставят на этот сайт плагин который показывает издевательское сообщение в стиле «скачай нормальный браузер» хотя мой меня вполне устраивает.
Зато они всегда рады устроить вой по поводу документов в формате ворд, хотя это формат существует уже лет 20, он самый популярный, хотя на сайте майкрософт можно скачать бесплатный просмотрщик документов этого формата для ОС Windows, который кстати в XP работает в отличие от их сайтов. И подробная спецификация на формат открыта и выложена.
Мне кажется, надо допилить ворд, чтобы при открытии созданного им документа в опенофисе там выводилось сообщение о неподдерживаемом редакторе и ссылка на сайт майкрософт.
По поводу скачай нормальный браузер, я их вполне поддерживаю. Все равно в вебе сейчас около 70%, наверное больше, на вебките и мозиле. И оба они почти одинаковые для юзера.
А формат документов, это другая парафия, когда документо оборот сложно организовать из-за стандарта, который диктует мелкософт, а не комьюнити, заставляя покупать их же софт.
Толстоват, зеленоват, молод и шутлив, но я отвечу:
>линупс, а не IIS
ну да конешно, тебе бы пришлось идти на принудительно-добровольную сертификацию микроманагеров, которые манагерят аспиксоблядей.
>2015
>IE
>WinXP
Сасай сразу и решительно. Тут даже болгенос с обоями получше будет
>word
Ага, особенно доставляют картиночки на вордклипе нарисованные, которые работают только в аутизм-боффисе2099, можно ведь нормальные открытые стандарты использовать, НЕТ хочу жрать говно, хочу слизывать говно с проприетарного ануса! Поэтому всякие манагеры и открывают ворд-вложения с эмейлами об увеличении пиниса, а потом думают что сисадмин-васян или прогер-петян им вырус занесли, ох ебаать.
Ну ты понял воощем
Какая разница кто диктует стандарт? Почему мы должны относиться к проблемам линуксоидов/маководов более внимательно чем к кроссбраузерности (которая влияет на большее число челоек)? Тем более что спецификация на ворд опубликована, можно ли называть его закрытым?
Ну и ворд используется уже 20 лет и всех кроме 0.0001% устраивает. Он проприетарен, но он не стоит каких-то больших денег и не плох на мой взгляд (хотя у меня стоит опенофис — мне его хватает для моих задач и я прекрасно открываю доки и xls'ы).
>>489508
Для меня как для пользователя открытые стандарты не сильно отличаются от закрытых. Для меня удобство/неудобство определяется затраченным временем на решение проблемы, а не степенью открытости стандарта. Тем более что ворд ничуть не более закрыт чем HTML, спецификация опубликована
Для ворда можно скачать бесплатный просмотрщик и просматривать сколько угодно, а для современных сайтов надо переустанавливать ОС, скачивать современный браузер и тд, это гораздо больше возни. И мне современные браузеры доставляют неудобство, они едят память сильно и силно тормозят. Чем «картиночки на вордклипе» хуже флексбокса в верстке? Оба доставляют неудобства. Почему современные сайты не работают или тормозят в старой Опере?
При том что никакой объективной необходимости делать такие кривые сайты нет. Можно купить нормальный сертификат работающий везде, а не только на последнем маке, можно делать более простую верстку, можно использовать совместимый JS. Это не так сложно если ты грамотный разработчик.
Верстают реально плохо. Периодически я натыкаюьсь на сайты, на которых например прокрутка страницы в одном браузере идет со скоростью несколько кадров в секунду. другие при заходе на них начинают есть 40% процессора и раскручивать вентилятор. При том что в обоих случаях донести нужную информацию можно хоть на HTML4 черными буквами на белом фоне.
Вирусы в письмах по 2 причинам:
1) потому что пользователям разрешено запускать программы скачанные/присланные из интернета (очевидно если запретить то часть проблемы устранится)
2) система разделения прав не обновлялась с 70-х годов когда целью было защитить одногого пользователя мефнфрейма от другого. В наше время пользователь на компьютере один и цель защитить программы и данные друг от друга. Вирусу-вымогателю не нужны права администратора.
Хороший пример где эти задачи решены это мобильные ОС от Эппл. В Линуксе частично решена только первая проблема (как я понимаю, именно частично, в Убунте есть установка программ из интернета через клик, также можно скачать баш/перл/питон скрипт который может быть запустится от двойного клика).
Также, есть 3-я причина:
3) узявимости в привилегированных компонентах могут позволить нарушить безопасность даже решившей первые 2 проблемы системы.
Что я хотел сказать? что твой намек «в виндоус вирусы, а линукс нет» ничем не подкреплен и система безопасности в линуксе ничем не лучше. Кстати, виндоус сертифицирован в плане безопасности, там есть мандатный доступ и все что требуется по стандарту.
Последние версии IE успешно соблюдают все стандарты, никакого отличия от Chrome и FireFox не будет. А вот XP уже не поддерживается, на нее сейчас даже жаба не ставится, IIS тоже.
> Тем более что ворд ничуть не более закрыт чем HTML, спецификация опубликована
Не полностью. Версия, используемая в офисе, имеет расширения по сравнению с опубликованным стандартом OOXML.
Старые форматы DOC/XLS/PPT открыты, но ими уже почти никто не пользуется.
> в виндоус вирусы, а линукс нет
В линукс вирусы есть (в основном ворующие деньги):
https://slon.ru/posts/50404
http://4pda.ru/2014/04/07/151901/
http://habrahabr.ru/post/255417/
http://androidinsider.ru/tag/virusyi
http://vms.drweb.ru/search/?q=Android.SmsSend
там типа бложик на MVC , "сделать новйы коммент не робит"
http://pastebin.com/T2HiFx7U
>спецификация опубликована
Да, но только единственная в мире программа способна работать с такими документами правильно (имеется ввиду правильность отображения и шоб как все у людей)
>а для современных сайтов надо переустанавливать ОС, скачивать современный браузер и тд, это гораздо больше возни
А кто виноват в том что у тебя старый браузер или ось? Верстальщик? Конечно поддержку старых браузеров можно обговорить с клиентом, но это время и деньги, клиенты в основном не парятся по воводу старых браузеров (если только в искл. случаях). С хера ли должен верстальщик тратить ещё часов 20 своего личного времени на ИЕ, я сказал именно ИЕ, в большинстве случаев только в нем может что-то пойти не так.
Видите ли закон Мура вроде как работает, но проблема в том что это переизбыток, рынок насыщен, а старые девайсы могут работать ещё хоть 10 лет и они уйдут на помойку истории, как и мы с вами когда-нибудь, так что смело можно обвинять все человечество в пиздабольстве и похуизме.
>можно делать более простую верстку
>При том что в обоих случаях донести нужную информацию можно хоть на HTML4 черными буквами на белом фоне.
Хотелки, перделки и передумки клиентов с вами не согласны.
>«Grammar Nazi». Напиши скрипт, проверяющий текст на наличие злостных ошибок:
>потому что пользователям разрешено запускать программы скачанные/присланные из интернета (очевидно если запретить то часть проблемы устранится)
Запретить? Серьезно? Все в основном в компаниях так и общаются, при помощи эмейлов и аттачментов к ним.
>Хороший пример где эти задачи решены это мобильные ОС от Эппл
Про эппл, хорошая статья: http://habrahabr.ru/company/dsec/blog/256407/
Для андройда был пример вируса, который использовал уязвимость обработки манифест xml файла, при установке писалось что будет использовать только список контактов, а на деле гораздо больше
>что твой намек «в виндоус вирусы, а линукс нет»
Ну такого я точно не намекал, для линупса есть всякие вирусы и руткиты, стоит линупсу стать таким же популярным как и шинда, то будет все тоже самое, но я хотел сказать точно что проприетарные системы это анальная боль безопасности и закрытость кода не делает продукт безопаснее, она делает его решетом, вот и все.
>виндоус сертифицирован в плане безопасности
Считаю что с этой бумажкой васян666 не сможет обойти систему защиты примитивными способами с дефолтными настройками, ок. Но этот сертификат не меняет вообще ни-че-го. Системы ломались, заражались так и будет все ломаться и заражаться, а сертификат будет на стеночке сиять, ага.
у тебя там в переменной $time что лежит? Уж не строка ли часом вида "xx:yy:zz"? Инче как ты дату или хотя бы время в виде числа умудрился записать? Время в виде числа с точкой что ли?
> С хера ли должен верстальщик тратить ещё часов 20 своего личного времени на ИЕ, я сказал именно ИЕ, в большинстве случаев только в нем может что-то пойти не так.
This. Проблемы нищебродов с XP - это их проблемы. Пускай Хром ставят.
> стоит линупсу стать таким же популярным как и шинда, то будет все тоже самое
Как бы уже, андроид это тоже линукс. А еще есть вирусы, заражающие embedded линукс (модемы и др.), недавно была статья на хабре.
Какой у тебя доход и почему хочешь перекатиться? Алсо делая такой скудный пост, ты ждешь развернутый ответ или как?
>Какие могут быть подводные камни в упомянутом съёбе?
Думаю что это работа за 10к хорошо если не за 5 пока ты простой макак гоняющий туда-сюда строчки
Около 50к у меня доход (миллионник-не-ДС), проблем с поиском работы в 1с-ке нет есличо, хотя увольняюсь часто дохуя в последнее время. перекатиться хочу, ибо заебло эпически. в 1с-ке от умения реально нихуя не зависит, по моим ощущениям, а только от умения заниматься рутиной. Плюс от того же php потом можно будет перекатиться как к другим языкам, так и к вёрстке либо SEO, в общем простор. А 1с-ка эта - тупик.
На определённое снижение дохода готов первое время, но 10к - разве что на несколько месяцев, пока стажировка.
> Около 50к у меня доход
Маловато для 1C-ника. Мои знакомые получают 100-150к (в мухосранске), пока я пишу код на жабе за еду (25к).
Я хуй знает, 100к это так-то дохуя, тем более для мухосрани. Они тебя не наёбывают? В любом случае, мне это вряд ли светит, ибо у меня от 1с-ки пукан рвётся уже.
>На определённое снижение дохода готов первое время, но 10к - разве что на несколько месяцев, пока стажировка.
Ну ты должен понимать, что в новой сфере всем будет срать какой ты там одинэсник. Если ты будешь быстро качаться то и будешь быстро повышать свой доход. А так кто-то может годами набирается опыта, что бы иметь такой доход. Если у тебя знакомые есть, уровня начальника отдела, которые пригреют тебе место, и быстро помогут прокачаться, то может и взлетит. А если ты собрался с 0 сам прийти такой пиздатый 30 летний дядя, и на собеседовании заявить, что нихуя не зная сейчас хочешь иметь через несколько месяцев свои 50к, то тебя ожидает лишь фрустрация
Понял тебя, ну я примерно этого и ожидал же. Есличо вернуться всегда ведь можно.
Может, можно что-нибудь такое относительно быстро в php замутить, чтобы не смотрели совсем уж как на говно? Сертификация там какая-нибудь или типа того.
Я не думаю что он или ему пиздят, все дело в том, что бы уметь себя(свои скиллы) продать в нужное место. Всегда есть вещи которые отделяют действительно прокачанного специалиста от обычной макаки. Или ты хочешь сказать что знаешь о своей 1с действительно все и можешь на изичах устроиться на любую вакансию?
Признайся что ты просто ничего и не делаешь кроме своей рутины, и всех это устраивает. но вечерами на кухне за рюмкой водки ты бьешь кулаком по столу и выкрикиваешь громко: НУ ВСЕ, С МЕНЯ ХВАТИТ! А на утро ничего не меняется Так будет везде. Я вот пхп макака и тут нет никакого блядь роста ПРОСТО ТАК САМО ПО СЕБЕ, НУ ПОРАБОТАЛ ГОДИК И СТАЛ МИДОМ. Тут не будет левелапа если ты перегнал миллион строк из контролера во вьюху. Это такая же рутина. А качаться нужно по болшей части в свободное от рабочей рутины время: либо опять же на работе делать что-то вместо хуепинания, либо браться за задачи где нужно прыгать выше головы, либо дома дрочить, мой друг.
Но признайся, Сём, если бы он написал 500к - ты бы ответил то же самое?
Не получают в Мухосрани 1с-ники сотку, никак. Либо какие-то охуенные менеджеры (и то вряд ли), либо же очень упёртые фрилансеры (там хуй знает вообще).
Ну да. Там я не очень в теме - ну может, кто упоротый сотку и поднимает. Я про свой ДС-3
Не ну это уже грубо с твоей стороны и попахивает подрывом пукана, как тут принято говорить. Я не шарю в 1С. Я лишь сужу по своему жизненному опыту и опыту работы эникеем. При этом есть знакомые админы которые в ДС получают 50, а есть которые в мухосрани получают 100+. Что уж говорить о разрабах из мухосрани которые имеют 150+ сейчас. В общем да, я конечно же семен и пиздабол, только смотри как бы твой маня-мир не лопнул вскоре. Ну как начнешь перекатываться в веб, удачи.
Ну вот например вакансия в Нижнем Новогороде, 1C от 90к:
http://hh.ru/vacancy/13471279?query=1%D0%A1
Статья говорит только о том что экосистема эппл не полностью соответствует описанным мной принципам. Я привел ее в пример так как она ближе других операционных систем. Есть стереотип что линукс безопасен но как мы видим это не так, любой запущенный пользователем баш скрипт может например зашифровать все важные файлы и от этого нет никакой защиты (особенно легко вставить такой скрипт при контроле над сетью и попытке пользователя сделать curl example.com | base что сейчас рекомендуется для установки многих приложений).
> Все в основном в компаниях так и общаются, при помощи эмейлов и аттачментов к ним.
Прочти внимательно, речь шла про исполняемые файлы и скрипты, а не документы. При наличии песочницы из пункта 2 кстати это становится не так критично.
> Про эппл, хорошая статья
для этого надо заманить человека на свой вайфай или еще куда-то, как я понимаю, и он должен согласиться на установку. И надо получить какой-то там официальный сертификат, как минимум это деанон и там куча ограничений:
> на устройствах можно запускать код, подписанный developer-сертификатом, выданным Apple-разработчику для конкретного устройства ( не более 100 заранее оговоренных устройств – необходимо знание UUID )
тебе нужно явно узнать и прописать UUID
> В-четвертых, приложения, подписанные enterprise-сертификатом
Который тебе никто не даст
> Читатель, знакомый с механизмами безопасности iOS, может отметить, что после попадания приложения на iOS-устройство оно работает в своем собственном, ограниченном, отделенном от всех sandbox…
Вот, опять же все дело в не до конца сделанной песочнице, как я понимаю эппл (ради своих системных приложений) там нагородила костылей для обхода песочницы и общения с привилегированными приложениями и этим пользуются.
Справедливости ради, что-то я пока не слышал про эпидемии вирусов под айфон.
> Для андройда был пример вируса, который использовал уязвимость обработки манифест xml файла, при установке писалось что будет использовать только список контактов, а на деле гораздо больше
Это пункт 3 который я помянул, уязвимости в привилегироанных компонентах. Мне кажется для борьбы с ними надо:
— минимизировать объем привилегироанного кода
— использоать безопасные техники программирования, условно говоря не использовать сишные строковые функции которые с близкой к 100% вероятностью ведут к buffer overflow, использовать безопасные методы работы с памятью (или вообще писать все на языках вроде явы где этой проблемы нет)
> Но этот сертификат не меняет вообще ни-че-го.
Этот сертификат доказывает что система соответствует требованиям, поддерживает мандатный доступ, очистку исплоьзованной памяти, но она не гарантирует что с дефолтными настройками система защищена. Кстати у линукса у каких-то дистрибутовов тоже что-то похожее есть, но там как минимум selinux нужен так как по дефолту в линуксе рут не имеет никаких ограничений, а в винде такого бардака нет.
Спасибо.
Знаешь, ну допустим ты прав, а у меня манямирок. Но один хрен попробовать надо. Тем более, что на свою-то з/п в 1с-ку я вернусь всегда, если чото не понравится.
> При этом есть знакомые админы которые в ДС получают 50, а есть которые в мухосрани получают 100+
Скорее всего они работают на нескольких заказчиков за меньшие деньги, потому что платить 100 000 просто админу большинство заказчиков удавится.
Изучай PHP, HTML, SQL (у вас есть аналог SQL так что дложно быть привычно), JS и если ты будешь стараться, думаю, все возможно. Веб не такой и сложный,а спрос на PHP-программистов в России второй после 1C.
SEO это та же рутина что 1с, сидеть составлять списки ключевых слов, покупать ссылки, прописывать метатеги, абсолютно унылое неинтеллектуальное занятие.
firststeps.ru/html/tutor/html1.html
htmlbook.ru
javascript.ru
php.su
proklondike.com/books/web.html
Дэвид Флэнаган - JavaScript. Подробное руководство
http://www.proklondike.com/books/javascript/david_flanagan_js_manual_5.html
Б. Маклафин - PHP и MySQL. Исчерпывающее руководство
http://www.proklondike.com/books/php/maklafin_php_mysql.html
По HTML/CSS сойдет любая книга, главное, чтобы описывались последние версии (HTML 5.0 и CSS 3.0).
>Прочти внимательно, речь шла про исполняемые файлы и скрипты, а не документы. При наличии песочницы из пункта 2 кстати это становится не так критично.
Да кто рассылает исполняемые файлы по эмейлу сейчас? Их по дефолту не пропускают любые мейловые серверы, сейчас делают инфицированные word доки и пдфки.
>Справедливости ради, что-то я пока не слышал про эпидемии вирусов под айфон.
Ловите макоёба!
> >Я о вирусных эпидемиях не слышал поэтому лучше чем линупс
Конкретно этой статьей не говориться что защита полный треш и пробить её действительно трудно, но не невозможно, давай-ка взглянем на историю фиксов критических уязвимостей в проприетарщине (уязвимый модуль обновления iTunes 3 года не фиксили) и в линупсе (готовые для всех платформ можно сделать буквально за несколько часов и пытливые админы с липкими от пива руками уже все пропатчат к утру и почесывая свою свободную-луних-бородку пойдут спать), я не говорю что хартблид и опеншурш это охуенно, но это лучше чем текущий ход событий в проприетарном рае
Не там просто UNIX timestamp лежит, вызванный функцией time(), который и есть интеджер, так что все должно быть ок, кстате можно было бы вместо этого написать функцию CURRENT_TIMESTAMP()
> готовые для всех платформ можно сделать буквально за несколько часов и пытливые админы с липкими от пива руками уже все пропатчат к утру и почесывая свою свободную-луних-бородку пойдут спать
Ты по моему ничего не понял. Линукс не соответствует описанным мной требованиям к безопасной системе. Там можно запускать код из интернета, нет песочницы и (как я понимаю) не применяются техники программирования для снижения риска возникновения уязвимости, объем привилегированного кода огромен и он увеличивается.
Патчи адресуют только третий пункт, про уязвимости в системных компонентах.
В базе есть типы данные специально для дат, DATETIME, DATE, TIMESTAMP и надо исопльзовать их, иначе это быдлокод получается.
То есть вот этой фразой
> все пропатчат к утру
ты мне рассказываешь как хорошо линуксоиды научились делать костыли к изначально небезопасной системе. По моему это то же самое что windows которую майкрософт патчат каждую неделю.
Но вредоносному коду не нужны уязвимости если ты можешь убедить пользоателя кликнуть по ссылке и запустить программу. И хорошая ОС либо не позволит запустиь этот код либо не позволит ему навредить пользователю.
Есть кстати и альтернативные способы обеспечить безопасность. Ну например если диск подключать в режиме read only и при перезагрузке компьютер полностью восстанавливает свое состояние, это тоже хорошее решение. Да, на такой компьютер нельзя ничего сохранить, но зато никакой вирус не помешает его пользователю читать сайты в интернете.
А старые данные из файла подкачки не используются при перезапуске (для надежности можно вообще удалять его, но это невыгодно).
>Линукс не соответствует описанным мной требованиям к безопасной системе
Конечно не будет, потому что это система изначально не для пользователей, которые не думают то что они делают, понятное дело нужно смотреть то что ты запускаешь, а если система думает за пользователя то она довольно-таки сильно его ограничивает. Да кстате можно точно также в винде запустить .bat файл и если установлен powershell то вообще хорошо
>не применяются техники программирования для снижения риска возникновения уязвимости
Не особо понял о каких техниках идет речь? Если ты о техниках контроля памяти и предотвращения популярного bufferoverflow, то добро пожаловать в реальность, там это делают не все, а те кто делают, делают только свою часть (им некогда следить за остальной командой)
>объем привилегированного кода огромен и он увеличивается
Это действует на все системы, включая и макось и линух и шинду и прочий софт, это просто не избежно и код всегда будет расти и расти. Так что не аргумент мань.
> >про уязвимости в системных компонентах
>openssl
>системный компонент
нет, это отдельный пакет
>изначально небезопасной системе
Вижу перед собой сотни безопасных IIS и Эплсерверов, нба не страшно.
>Но вредоносному коду не нужны уязвимости
И да и нет. Это всего лишь один из путей того как делать что-либо, можно сделать и такой вирус который будет использовать уязвимости для получения админ прав например.
>ты можешь убедить пользоателя кликнуть по ссылке и запустить программу. И хорошая ОС либо не позволит запустиь этот код либо не позволит ему навредить пользователю.
Хорошая OС спросит конечно же, но мы же уже убедили пользователя запустить?
Представляю тонны каждодневных жалоб от манагеров, бухгалтеров и директоров всяких, уборщиц которые жалуются на то что им нужно открыть что-то срочно, а компуктер постоянно спрашивает, шо мол опасно. Им нужно здесь и сейчас, поэтому понятие "хорошая ОС", крайне расплывчато в понимании обычных людей.
>этот код либо не позволит ему навредить пользователю.
А как не навредить? Каким образом ОС установит какой код вредящий, а какой щедящий? Антивирусники могут эврестической просмотреть что да как, но всегда ли сработает? И антивирусник это уже другая программа и не поставляется вместе с ОС.
> Да кстате можно точно также в винде запустить .bat файл и если установлен powershell то вообще хорошо
Потому что, как я написал в самом первом посте, они (и linux и windows) используют модели безопасности из 70-х придуманные для многопользовательских майнфреймов. Очевидно они устарели и неактуальны. Более того, мандатный доступ что в линукс что в виндоуз для домашнего пользователя бессмысленнен так как он может загрузиться с live cd/вынуть жесткий диск и сделать с ним что угодно. Они поставляют систему разделения прав которая не защищает от вирусов и которая только мешает постоянно выскакивающими окнами ввода пароля.
> то добро пожаловать в реальность, там это делают не все, а те кто делают, делают только свою часть (им некогда следить за остальной командой)
Это легко поменять, если есть воля мейнтейнера: он может выработать стандарты и отказываться от несоблюдающих их патчей.
Но в случае с линуксом, его главный разработчик например даже Си++ не готов рассматривать, я думаю рано или поздно это огромное монолитное ядро умрет, так как его будет нереально поддерживать на Си.
> Это действует на все системы, включая и макось и линух и шинду и прочий софт, это просто не избежно и код всегда будет расти и расти.
Неверно. Он не обязан расти, код можно дробить, унифицировать, привилегии можно дробить, есть микроядерные архитектуры. Рано или поздно мы к этому придем иначе монолитное многомегабайтное ядро будет как решето.
> openssl
Я говорю про работчие и домашние компьютеры. У сервера есть квалифицированный админ, и там проблема безопасности не стоит остро. даже если его заразят, админ отформатирует диск и все переустановит, а кто поможет обычному пользователю, не разбирающемуся в компьютерах? Они все больше входят в нашу жизнь, через них мы делаем платежи и нам нужна надежная система которой можно доверять. Сотни миллионов человек пользуются компьютерами сегодня,миллиарды присоединяться к ним завтра, и часть из них даже писать не умеет.
Современные компьютеры это именно что артефакты из прошлого:
— система разделения доступа от 70-х которыя ни от чего не защищает
— файловая система которая позволяет с легкостью удалить важный файл без возможности простого восстановления
— обновления, загрузки, загрузи програимму, установи обновление, пусть твой работодатель платит за потерянное время
— вводимые с клавиатуры пароли (!) которые должны содержать минимум 8 символов которые ты должен помнить наизусть (!) и которые для каждого сайта должны быть свои (!). Я должен помнить пароли просто для того чтобы пользоваться интернетом или заплатить за что-нибудь? При этом любой вирус перехватывающий нажатия клавиш может скопировать мой пароль и украсть мой аккаунт со свиньями девятого уровня? Ну не дебилы ли придумали такую систему, а?
Дебилы-инженеры, не знают что человечество давно придумало более удобный и надежный токен доступа под названием ключ.
Что делает человек в ответ на такое насилие? правильно, ставит галочку «запомнить пароль» и отключает пароль при входе на десктоп. Глупые инженеры застрявшие в 80-х, вы хотели сделать систему безопаснее, вы сделали ее менее безопасной. Что делает Эппл? Кнопку разблокировки с сканером пальца.
— до сих пор на клавиатуре можно найти бессмысленные клавиши вроде caps lock, sys rq (wtf? это клавиша с майнфреймов из 70-х?) или insert зато нельзя найти клавишу с российским флагом или клавишу переключения на кандзи, а русские буквы объединены на одной клавише со знаками пунктуации и запятая в разных раскладках находится на разных клавишах. Ну не дебилы, а? И это делают мировые корпорации у которых денег больше чем в бюджете средней страны.
Хватит это терпеть. Пора сделать новую платформу, которая сотрет эти айбиэмовские пережитки как смартфоны стерли телефоны прошлого. Кстати на смартфонах нет бессмысленных клавиш и другие системы разграничения доступа. думаю, пришла очередь десктопов.
Ну а насчет ключей для доступа: гугл кажется что-то делает в этом направлении: http://m.habrahabr.ru/company/otr_to/blog/259331/
> Да кстате можно точно также в винде запустить .bat файл и если установлен powershell то вообще хорошо
Потому что, как я написал в самом первом посте, они (и linux и windows) используют модели безопасности из 70-х придуманные для многопользовательских майнфреймов. Очевидно они устарели и неактуальны. Более того, мандатный доступ что в линукс что в виндоуз для домашнего пользователя бессмысленнен так как он может загрузиться с live cd/вынуть жесткий диск и сделать с ним что угодно. Они поставляют систему разделения прав которая не защищает от вирусов и которая только мешает постоянно выскакивающими окнами ввода пароля.
> то добро пожаловать в реальность, там это делают не все, а те кто делают, делают только свою часть (им некогда следить за остальной командой)
Это легко поменять, если есть воля мейнтейнера: он может выработать стандарты и отказываться от несоблюдающих их патчей.
Но в случае с линуксом, его главный разработчик например даже Си++ не готов рассматривать, я думаю рано или поздно это огромное монолитное ядро умрет, так как его будет нереально поддерживать на Си.
> Это действует на все системы, включая и макось и линух и шинду и прочий софт, это просто не избежно и код всегда будет расти и расти.
Неверно. Он не обязан расти, код можно дробить, унифицировать, привилегии можно дробить, есть микроядерные архитектуры. Рано или поздно мы к этому придем иначе монолитное многомегабайтное ядро будет как решето.
> openssl
Я говорю про работчие и домашние компьютеры. У сервера есть квалифицированный админ, и там проблема безопасности не стоит остро. даже если его заразят, админ отформатирует диск и все переустановит, а кто поможет обычному пользователю, не разбирающемуся в компьютерах? Они все больше входят в нашу жизнь, через них мы делаем платежи и нам нужна надежная система которой можно доверять. Сотни миллионов человек пользуются компьютерами сегодня,миллиарды присоединяться к ним завтра, и часть из них даже писать не умеет.
Современные компьютеры это именно что артефакты из прошлого:
— система разделения доступа от 70-х которыя ни от чего не защищает
— файловая система которая позволяет с легкостью удалить важный файл без возможности простого восстановления
— обновления, загрузки, загрузи програимму, установи обновление, пусть твой работодатель платит за потерянное время
— вводимые с клавиатуры пароли (!) которые должны содержать минимум 8 символов которые ты должен помнить наизусть (!) и которые для каждого сайта должны быть свои (!). Я должен помнить пароли просто для того чтобы пользоваться интернетом или заплатить за что-нибудь? При этом любой вирус перехватывающий нажатия клавиш может скопировать мой пароль и украсть мой аккаунт со свиньями девятого уровня? Ну не дебилы ли придумали такую систему, а?
Дебилы-инженеры, не знают что человечество давно придумало более удобный и надежный токен доступа под названием ключ.
Что делает человек в ответ на такое насилие? правильно, ставит галочку «запомнить пароль» и отключает пароль при входе на десктоп. Глупые инженеры застрявшие в 80-х, вы хотели сделать систему безопаснее, вы сделали ее менее безопасной. Что делает Эппл? Кнопку разблокировки с сканером пальца.
— до сих пор на клавиатуре можно найти бессмысленные клавиши вроде caps lock, sys rq (wtf? это клавиша с майнфреймов из 70-х?) или insert зато нельзя найти клавишу с российским флагом или клавишу переключения на кандзи, а русские буквы объединены на одной клавише со знаками пунктуации и запятая в разных раскладках находится на разных клавишах. Ну не дебилы, а? И это делают мировые корпорации у которых денег больше чем в бюджете средней страны.
Хватит это терпеть. Пора сделать новую платформу, которая сотрет эти айбиэмовские пережитки как смартфоны стерли телефоны прошлого. Кстати на смартфонах нет бессмысленных клавиш и другие системы разграничения доступа. думаю, пришла очередь десктопов.
Ну а насчет ключей для доступа: гугл кажется что-то делает в этом направлении: http://m.habrahabr.ru/company/otr_to/blog/259331/
Хорошая ОС не позволит потерять важные данные и не позволит вирусу нарушить работоспособность системы. Стереть и сломать он может только данные внутри своей песочницы.
> Это всего лишь один из путей того как делать что-либо, можно сделать и такой вирус который будет использовать уязвимости для получения админ прав например.
Если мы сможем победить хотя бы вирусы которые работают без уязвимостей это уже будет лучше чем то что сейчас.
> которые жалуются на то что им нужно открыть что-то срочно, а компуктер постоянно спрашивает, шо мол опасно
Вот видишь, ты мыслишь теми же стереотипами что инженеры из 80-х. Спросить пользователя? Ты это серьезно? Пользователь — это антивирусный эксперт который одним взглядом на иконку файла может определить безопасен ли он? Нет, пользователь это не может. И ты не можешь, и я не могу кроме каких-то простых случаев (если файл подписан известным вендором вроде Майкросфот или Мозиллы. А если его подписал Гугл — безопасен ли он или он будет перехватывать все посещаемые страницы и отправлять в Калифорнию? Хром так делает и он подписан).
Спрашивать пользователя бесполезно, потому мы должны либо запрещать запуск сомнительного кода либо гарантироать что он не навредит пользователю и его данным. Никакая программа не должна нарушить работоспособность компьютера, повредить хранящиеся данные или перехватить вводимую информацию.
> понятие "хорошая ОС", крайне расплывчато в понимании обычных людей.
Хорошая ОС это которая не ломается и не ломает данные, что ты с ней не делай и кого ты за нее не посади.
> А как не навредить?
Вот допустим мы создаем виртуальную машину, ставим туда Windows и запускаем программу там. Может ли она навредить хост-машине? Наверно в теории может но поверхность атаки очень маленькая, код изоляции небольшой и может быть тщательно проверен. Виртуальная машина это просто пример, на самом деле там может использоваться любой другой подход.
Или ты открываешь сайт, а Хром запускает для него отедльный процесс с пониженными до минимума привилегиями, как итог на конкурсах по взлому браузеров за Хром платят самую большую награду — это сложнее всего сделать.
Надо мыслить и искать пути решения проблем а не копироать устаревшие подходы из эпохи майнфреймвов. Я надеюсь что рынок захватит тот, кто принесет нам новые платформы, а не полумертввая IBM PC/Windows.
> Антивирусники могут эврестической просмотреть
Любой уважающий себя взломщик проверяет свои вирусы на обнаружение и таким образом эта «эвристика» бесполезна. Не говоря о том что нет гарантированного способа определить вредоносность программы за приемлемое время. Антивирус это костыль к непраивльно спроектировнной системе.
Хорошая ОС не позволит потерять важные данные и не позволит вирусу нарушить работоспособность системы. Стереть и сломать он может только данные внутри своей песочницы.
> Это всего лишь один из путей того как делать что-либо, можно сделать и такой вирус который будет использовать уязвимости для получения админ прав например.
Если мы сможем победить хотя бы вирусы которые работают без уязвимостей это уже будет лучше чем то что сейчас.
> которые жалуются на то что им нужно открыть что-то срочно, а компуктер постоянно спрашивает, шо мол опасно
Вот видишь, ты мыслишь теми же стереотипами что инженеры из 80-х. Спросить пользователя? Ты это серьезно? Пользователь — это антивирусный эксперт который одним взглядом на иконку файла может определить безопасен ли он? Нет, пользователь это не может. И ты не можешь, и я не могу кроме каких-то простых случаев (если файл подписан известным вендором вроде Майкросфот или Мозиллы. А если его подписал Гугл — безопасен ли он или он будет перехватывать все посещаемые страницы и отправлять в Калифорнию? Хром так делает и он подписан).
Спрашивать пользователя бесполезно, потому мы должны либо запрещать запуск сомнительного кода либо гарантироать что он не навредит пользователю и его данным. Никакая программа не должна нарушить работоспособность компьютера, повредить хранящиеся данные или перехватить вводимую информацию.
> понятие "хорошая ОС", крайне расплывчато в понимании обычных людей.
Хорошая ОС это которая не ломается и не ломает данные, что ты с ней не делай и кого ты за нее не посади.
> А как не навредить?
Вот допустим мы создаем виртуальную машину, ставим туда Windows и запускаем программу там. Может ли она навредить хост-машине? Наверно в теории может но поверхность атаки очень маленькая, код изоляции небольшой и может быть тщательно проверен. Виртуальная машина это просто пример, на самом деле там может использоваться любой другой подход.
Или ты открываешь сайт, а Хром запускает для него отедльный процесс с пониженными до минимума привилегиями, как итог на конкурсах по взлому браузеров за Хром платят самую большую награду — это сложнее всего сделать.
Надо мыслить и искать пути решения проблем а не копироать устаревшие подходы из эпохи майнфреймвов. Я надеюсь что рынок захватит тот, кто принесет нам новые платформы, а не полумертввая IBM PC/Windows.
> Антивирусники могут эврестической просмотреть
Любой уважающий себя взломщик проверяет свои вирусы на обнаружение и таким образом эта «эвристика» бесполезна. Не говоря о том что нет гарантированного способа определить вредоносность программы за приемлемое время. Антивирус это костыль к непраивльно спроектировнной системе.
Кстати, говоря о серверах, в линуксе все ничем не лучше. Допустим ты хочешь установить на сервер модную NoSQL базу данных N о которой прочел вчера на хабре. Ты заходишь на сайт, и там большими буквами написано:
Installation couldn't be easier! To install N just type
curl http://example.com | sudo bash
in your terminal and in a minute you will be able to use all of the awesome features that 20 million users have chosen bla bla bla
Разумеется, чтобы пользоваться программой N ты должен также залогиниться через твиттер, фейсбук или гитхаб-аккаунт.
Нет, там перки в узких специализациях. Собственно в веб-макакинге мне все видится почти таким же.
И если область узкая, то это не значит что там все изи можно натаскаться за месяц. Там так же люди учатся годами. Суть в том, что специалисты не берутся из ниоткуда. Нельзя взять с улицы васю, который за месяц САМ РАЗБЕРЕТСЯ, ну вы поняли.
>>489736
А какой у тебя план? Ты уже выучил что-нибудь? И вообще, чем ты на своей работе занимался? Ты был 1С-программистом спецназом-элитой среди всех программистов или каким-нибудь менеджером-втюхивальщиком? Может быть вообще какой-нибудь 1С-оператор-синьор, что и расти некуда больше. В чем заключалась твоя рабочая рутина? Вангую вообще не поможет тебе это во вкатывании в веб, но все равно расскажи.
>Потому что, как я написал в самом первом посте, они (и linux и windows) используют модели безопасности из 70-х придуманные для многопользовательских майнфреймов. Очевидно они устарели и неактуальны. Более того, мандатный доступ что в линукс что в виндоуз для домашнего пользователя бессмысленнен так как он может загрузиться с live cd/вынуть жесткий диск и сделать с ним что угодно. Они поставляют систему разделения прав которая не защищает от вирусов и которая только мешает постоянно выскакивающими окнами ввода пароля.
Все тоже самое можно сделать и с макосью (запустить скрипт, тот же livecd), поэтому все очень плохо
>Ключи доступа
Ну да, а потом мы в лоб столкнемся с проблемой похищений и выманиваний этих ключей, проблем доверия к выдающему ключи и возможно устаревающие алгоритмы и опять все по новой: методички по сохранению ключей (вместо запоминания сложных паролей) ещё можт и тренинги сделают лол
>Хватит это терпеть. Пора сделать новую платформу, которая сотрет эти айбиэмовские пережитки как смартфоны стерли телефоны прошлого. Кстати на смартфонах нет бессмысленных клавиш и другие системы разграничения доступа. думаю, пришла очередь десктопов.
Ага стерли они телефоны прошлого, телефоны прошлого на сегодняшних аккумах могут работать гораздо дольше чем современные пукалки с АРМ (которые скоро встретит свой потолок), бэкграундавыми тасками и коллекционированием ваших геоданных, что заставляет заряжать аккум как минимум раз в сутки.
Ну и что же? Новая платформа будет чем-то лучше современных?
yupe
>Спросить пользователя? Ты это серьезно?
ИТшники за это деньги получают, до сих пор бы возились с перфокартами, потому что "это нельзя", "то нельзя", "ничего нельзя", а так пользователи получают то что они хотят, быстро, дешево и в один клик, именно за это они и плотят деньги.
>если файл подписан известным вендором вроде Майкросфот или Мозиллы
Где-то я видел описание про вредонос подписанный MailRuGroup или что-то в этом роде, проиграл тогда. Не удивлюсь если увижу подписанные от мелкософта.
>Хорошая ОС это которая не ломается и не ломает данные, что ты с ней не делай и кого ты за нее не посади.
Миф о неломаемости вещей. У кого-то жесткий диск полетел, это не проблема ОС, но и пожаловаться ты на неё не можешь т.к. ОС то хорошая, а вот железо плохое. Да и нету таких ОС в принципе которые гарантируют 100% сохранность ваших данных и тому подобное + нету таких ОС в которых нету багов (учитывая миллионы строк)
>Вот допустим мы создаем виртуальную машину, ставим туда Windows
Я думаю вы не слышали о вредоносах, которые могут детектировать то что они находятся в песочнице или виртуальной машине, так ведь? Я думаю это можно сделать.
>Любой уважающий себя взломщик проверяет свои вирусы на обнаружение
Имблаинг такие сервисы не сливают данные вендорам антивирусников об подозрительных файлах.
Какие вы все тут милые :3 Будто с доброчана пришли :3 подписался на тред.
мать твою ебал
>Разумеется, чтобы пользоваться программой N ты должен также залогиниться через твиттер, фейсбук или гитхаб-аккаунт.
Чего-то не видел таких. В основаном все открыто и клонировать с репозитория можно в открытую, без логинов
> Ну да, а потом мы в лоб столкнемся с проблемой похищений и выманиваний этих ключей,
Как ты эт представляешь? На улице что ли будут ключ доступа к вконтактику красть? По твоей логике ключи от дома и от машины тоже каждый день похищают и выманивают, от них надо отказаться?
Ну и ты можешь хранить ключ дома например и вообще с собой не носить.
>>490034
> У кого-то жесткий диск полетел
Ты впадаешь в крайности. Понятно что из другой галактики может прилететь заряженная частица и разнести процессор на кусочки, но мы говорим про более обыденные вещи вроде вирусов и троянов.
> которые могут детектировать то что они находятся в песочнице или виртуальной машине,
Ну детектировал и что? Конечно, это легко, в случаес виртуалбоксом достаточно посмотреть на версию биоса или название видеокарты.
> Имблаинг такие сервисы не сливают данные вендорам антивирусников об подозрительных файлах.
Потому уважающий себя хакер либо поднимает свой сервис либо пользуется андерграундным которым управляют надежные люди. Но суть не в этом,а в том что антивирус это костыль который пропускает первую волну атаки и может быть за это время семпл попадет к разработчикам и они добавят его в базу. А если это немассовый вирус вроде используемого американской разведкой то он может вообще никуда не попасть.
>>490037
Добра тебе, решай задачки.
>>490045
Часто бывает API в облаке, а ключ только через регистрацию или гитхаб или еще что-нибудб. Нашему отделу маркетинга и партнерам нужны конаткты теплых клиентов для продаж и рассылок.
Ну и тебе не кажется что воткнуть ключ в комьютер и нажать кнопку удобнее и безопаснее чем мучаться с паролями? Плюс при правильной криптографии софт на компьютере не может его украсть, ты можешь им хоть банковские транзакции авторизовывать (собственно юрлица примерно так и делают, только у них убогие проприетарные ключи. Конечно нам нужен хороший открытый стандарт разработанный профессионалами из кремниевой долины а не закрытый с кучей дыр написанный фрилансером Васей).
>Как ты эт представляешь? На улице что ли будут ключ доступа к вконтактику красть? По твоей логике ключи от дома и от машины тоже каждый день похищают и выманивают, от них надо отказаться?
Нет отказываться не надо, но надо показать что решение с ключами не много лучше паролей и будут другие способы раздобыть, сломать, скопировать и т.д.
>Ты впадаешь в крайности. Понятно что из другой галактики может прилететь заряженная частица и разнести процессор на кусочки, но мы говорим про более обыденные вещи вроде вирусов и троянов.
То есть помимо поголовной совместимости со всеми принтерами, сканерами и прочими девайсами, скоростью выполнения задач и обработки информации, ОС должна следить ещё и за тем кто-что делает что каждый момент времени, да ты издеваешься, каждый API колл будет анализироваться на наличие подозрительных вещей? Плюс не забывай, система защиты должна быть защищена сама по себе. И это будет великим мифом т.к. ничего не стоит дизассемблировать эту фишечку и найти бреши в самой системе защиты и только представь сколько строк кода в ней будет (а чем больше тем хуже для безопасности), на сколько сильно она будет тормозить систему и т.д.
> и будут другие способы раздобыть, сломать, скопировать
Главное что школьник Вася сидя за компьютером ничего украсть не сможет. И это вин. Ну и пароли запоминать не надо.
> каждый API колл будет анализироваться на наличие подозрительных вещей
Жаль но по моему ты так ничего и не понял.
>И это вин
Вася может быть и нет, но упертый петя например сможет
>Жаль но по моему ты так ничего и не понял.
Давай давай расскажи мне про
>хорошая ось которая ниломается никогда
Верстать и не придется скорее всего, если ты попадешь в нормальную фирму, а не дно-контору, где программист одновременно и верстальщик, и переговорщик, и уборщица.
Но знать тонкости html/css нужно идеально, потому что часто необходимо сгенерировать кусок html шаблона в php, а стили постоянно будет изменяться через javascript.
Ссылка - http://jsfiddle.net/d4a05n5w/2/
и кошак для привлечения внимания
Ему гитхаб дали, копайся в любом коде на любых языках. Нет, нехочу. Хочу говнокод анония пошатать.
В моем мухосрани 1С хорошо оплачивается - 40к, при том что ПХП - от 20к и то говноконторы, я бы даже его задрачил на первое время, останавливает то, что там указывают умение общаться с клиентами, а я хикка бля.
Про гитхаб слышал, даже заглядывал. Спасибо, пойду пороюсь, конечно. Но никто мне там толком ничего не пояснит, даже теоретически. Мне бы только сейчас аккуратненько вкатиться и прокачивать помалеху скиллы
Можешь начать с фреймворков. Сейчас в мейнстриме laravel, yii. Zend и symfony пока не трогай, они будут посложнее. Абстракция на абстракиции, абстракцией погоняет. Или микрофреймворки silex, slim. В документации к ним ко всем есть прмиеры простеньких приложений - блог, туду лис и тд.
Читаешь документацию, луркаешь на гитхабе "%framework_name% blog" и тому подобное. Повторить до наступления просветления.
Спасибо большое.
<?php
final class Foo
{
public method doFoo()
{
// do something useful and return a result
}
}
final class FooDecorator
{
private $foo;
public function __construct(Foo $foo)
{
$this->foo = $foo;
}
public function doFoo()
{
$result = $this->foo->doFoo();
// ... customize result ...
return $result;
}
}
?>
<?php
final class Foo
{
public method doFoo()
{
// do something useful and return a result
}
}
final class FooDecorator
{
private $foo;
public function __construct(Foo $foo)
{
$this->foo = $foo;
}
public function doFoo()
{
$result = $this->foo->doFoo();
// ... customize result ...
return $result;
}
}
?>
Знать нужно, верстать нет, это задача front end'щика и дизайнера.
Да, я знаю, что оп фанат симфони, но а вдруг?...
Yii оп вроде знает, но вообще поддержка Yii ужасна, на половину не работающие мануалы, старые и новые версии, ах, да, мне еще CRUD не понравился там.
1) читай учебники на сайтах htmlbook, htmlacademy
2) решай наши задачи на HTML/CSS которые приведены в ОП-посте и выкладывай ссылки на решения, я дам советы и замечания
После HTMl/CSS можешь переходить к JS, сайт learn.javascript.ru, задачи в ОП посте.
Тогда это не программист, а какой-нибудь продажник или настройщик. Я видел 1с программистов (студентоту правда), они весь день сидели писали код и с клиентами не разговаривали даже по телефону.
Ты странные советы даешь. Как я понимаю, анон даже PHP пока не знает, не говоря об ООП и MVC, ему рано за фреймворки браться. Если он не знает PHP то ему стоит начать с основ, ссылка на учебник стоит в ОП посте.
Ок, я глянул код, вот что стоит поправить:
> https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L57
> public function searchFromStudents($string = '')
Я не вижу тут постраничной выборки. То есть если тебе надо отобразить на странице 10 студентов ты зачем-то выбираешь все 1000 студентов из базы. Это неэффективно и неправильно, используй LIMIT чтобы выбрать только нужные нам строки из базы. Должны выбираться только те строки, которые отображаются, а не все подряд.
> https://github.com/Si0n/register3/blob/master/lib/paginator.php
Пагинация получилась на мой взгляд, неудачная и запутанная. У тебя пагинатор может работать только с одной таблицей студентов. Фактически это не отдельный пагинатор, а продолжение файла list_action.php. Причем там много переменных и трудно понять какие приходят из list_action.php, какие передаются в шаблон, какие просто временные. Такого быть не должно. В таких случаях код надо разбивать на функции или делать в виде класса.
Хорошо бы было сделать универсальный пагинатор работающий с любыми данными, который можно использовать в любом проекте. Он делается так, делаем например класс Pager и используем его так:
$total = всего студентов;
$page = номер текущей страницы;
$perPage = число студентов на одной странице;
// создаем объект-пагинатор
$pager = new Pager($page, $perPage, $total);
// задаем шаблон ссылки
$pager->setLinkTemplate('index.php?p={page}');
....
А затем в шаблоне используем его так:
<?php foreach ($pager->getPagination() as $title => $url): ?>
<a href="<?= html($url) ?>"><?= html($title) ?></a>
<?php endforeach ?>
Код класса Pager я думаю, ты можешь легко написать сам. Попробуй сделать такой пагинатор, который не привязан к конкретной таблице и который можно использовать с любыми данными. Если надо, можешь попросить еще подсказку.
Сейчас у тебя есть 2 папки, lib и scripts. В lib лежат как файлы с классами, так и без классов. В scripts лежит один отдельный файл. Надо как-то разобраться и может быть положить файлы с классами в одну папку, а без классов в другую.
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php
то, что в этом файле, нужно перенести в ini.php
> https://github.com/Si0n/register3/blob/master/index.php#L3
> require './template/main.php';
Ты подключаешь зачем-то шапку страницы в начале index.php, зачем? Ведь во-первых у тебя может быть страница на которой не нужна эта шапка, во-вторых, после ее подключения ты не можешь отправлять заголовки, ставить куки, делать редирект (который тебе понадобится при работе с формой). Я думаю этот инклюд надо убрать и переставить в шаблон.
> https://github.com/Si0n/register3/blob/master/index.php#L2
> $include = $_GET['page'];
Если ты не передаешь параметр page то тут будет ошибка доступа к несуществующему элементу массива. Видишь ли ты ее? Если нет то проверь включено ли у тебя отображение ошибок в браузере (display_errors). А если видишь, почему не исправил?
> switch ($include) :
Тут надо использоать не версию с двоеточием, а версию со скобками: switch (...) { ... }. Также, тут должен быть default, а то непонятно что у тебя выведется если $_GET['page'] неправильный или не указан.
> case 'list' : include ('./lib/list_action.php'); break;
> if (isset($_GET['search'])) {
> include('./lib/list_action.php');
Если у тебя $_GET['page'] содержит 'list' и $_GET['search'] не пустой, то файл подключится 2 раза. Такого быть не должно. Этот if лучше убрать вообще и сделать как-то по-другому.
> https://github.com/Si0n/register3/blob/master/index.php#L13
> require './template/footer.php';
Это надо подключать из шаблона. Может нам понадобится нестандартный футер где-то, а не одинаковый для всех.
> https://github.com/Si0n/register3/blob/master/lib/list_action.php#L2
> include 'ini.php';
По моему у тебя этот файл подключается несколько раз. Сделай чтобы подключался только один раз, например в index.php.
> $db = new StudentsMapper($pdo);
То же самое. Можно создавать этот объект только один раз в ini.php, а не в нескольких местах.
> makeProtect( $_GET['search'] ) :
Эту функцию надо назвать лучше. «сделать защиту» не объясняет что она делает. Мне кажется, там должно использоваться слово вроде html, так как фактически это обертка над htmlspeialchars.
Более того, я думаю что эта функция тут вообще не нужна. Ты должен делать htmlspecialchars при выводе данных в шабоне, а не тут. Тут это не имеет никакого смысла, тут это скорее навредить может поиску, так как заменяет некоторые символы на последовательность вроде &
> https://github.com/Si0n/register3/blob/master/lib/functions.php#L8
> return makeProtect($_COOKIE[$name]);
Это неправильно. Экранировать данные надо там, где они используются, то есть в шаблоне. Функция getCookie должна просто возвращать точное значение куки и не пытаться заменять в ней символы. Ну сам подумай, как можно писать надежный код с функцией которая возвращает не точные, а измененные данные?
> if (count($data) == 0)
> $text = ' <br> Нет совпадений в базе студентов.';
HTML-теги должны быть в шаблоне, тут их быть не должно. Предупреждение должно выводиться только при неудачной попытке поиска, а если например база пустая то текст должен быть другой.
> https://github.com/Si0n/register3/blob/master/lib/paginator.php#L2
> require_once(__DIR__ . './functions.php');
Этот реквайр надо убрать и перенести в ini.php
> https://github.com/Si0n/register3/blob/master/lib/paginator.php#L4
> makeProtect( $_GET['p'] )
Тут уместнее использовать intval так как номер страницы должен быть числом
> $currentURL = '?search={search}&p={page}';
> $currentURL = str_replace('{search}', $search, $currentURL);
При подстановке данных в URL надо обрабатывать их через urlencode чтобы спецсимволы кодировались процентным кодированием ( https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Более того, в PHP есть стандартная функция для сборкии таких URL, она называется http_build_query, используй ее в таких случаях.
> https://github.com/Si0n/register3/blob/master/template/list.php#L22
> <td><?= $data[$k]['Surname'] ?></td>
Данные которые ты выводишь в шаблоне, должны быть экранироаны функцией htmlspecialchars для предотвращения XSS уязвимости и проблем с отображением спецсимволов вроде <. В имени конечно такие символы вряд ли встретятся, но проще экранировать все, чем разбираться что там может встретиться, а что нет.
Если что-то непонятно, или нужна подсказка, или хочешь посоветоваться, пиши.
Ок, я глянул код, вот что стоит поправить:
> https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L57
> public function searchFromStudents($string = '')
Я не вижу тут постраничной выборки. То есть если тебе надо отобразить на странице 10 студентов ты зачем-то выбираешь все 1000 студентов из базы. Это неэффективно и неправильно, используй LIMIT чтобы выбрать только нужные нам строки из базы. Должны выбираться только те строки, которые отображаются, а не все подряд.
> https://github.com/Si0n/register3/blob/master/lib/paginator.php
Пагинация получилась на мой взгляд, неудачная и запутанная. У тебя пагинатор может работать только с одной таблицей студентов. Фактически это не отдельный пагинатор, а продолжение файла list_action.php. Причем там много переменных и трудно понять какие приходят из list_action.php, какие передаются в шаблон, какие просто временные. Такого быть не должно. В таких случаях код надо разбивать на функции или делать в виде класса.
Хорошо бы было сделать универсальный пагинатор работающий с любыми данными, который можно использовать в любом проекте. Он делается так, делаем например класс Pager и используем его так:
$total = всего студентов;
$page = номер текущей страницы;
$perPage = число студентов на одной странице;
// создаем объект-пагинатор
$pager = new Pager($page, $perPage, $total);
// задаем шаблон ссылки
$pager->setLinkTemplate('index.php?p={page}');
....
А затем в шаблоне используем его так:
<?php foreach ($pager->getPagination() as $title => $url): ?>
<a href="<?= html($url) ?>"><?= html($title) ?></a>
<?php endforeach ?>
Код класса Pager я думаю, ты можешь легко написать сам. Попробуй сделать такой пагинатор, который не привязан к конкретной таблице и который можно использовать с любыми данными. Если надо, можешь попросить еще подсказку.
Сейчас у тебя есть 2 папки, lib и scripts. В lib лежат как файлы с классами, так и без классов. В scripts лежит один отдельный файл. Надо как-то разобраться и может быть положить файлы с классами в одну папку, а без классов в другую.
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php
то, что в этом файле, нужно перенести в ini.php
> https://github.com/Si0n/register3/blob/master/index.php#L3
> require './template/main.php';
Ты подключаешь зачем-то шапку страницы в начале index.php, зачем? Ведь во-первых у тебя может быть страница на которой не нужна эта шапка, во-вторых, после ее подключения ты не можешь отправлять заголовки, ставить куки, делать редирект (который тебе понадобится при работе с формой). Я думаю этот инклюд надо убрать и переставить в шаблон.
> https://github.com/Si0n/register3/blob/master/index.php#L2
> $include = $_GET['page'];
Если ты не передаешь параметр page то тут будет ошибка доступа к несуществующему элементу массива. Видишь ли ты ее? Если нет то проверь включено ли у тебя отображение ошибок в браузере (display_errors). А если видишь, почему не исправил?
> switch ($include) :
Тут надо использоать не версию с двоеточием, а версию со скобками: switch (...) { ... }. Также, тут должен быть default, а то непонятно что у тебя выведется если $_GET['page'] неправильный или не указан.
> case 'list' : include ('./lib/list_action.php'); break;
> if (isset($_GET['search'])) {
> include('./lib/list_action.php');
Если у тебя $_GET['page'] содержит 'list' и $_GET['search'] не пустой, то файл подключится 2 раза. Такого быть не должно. Этот if лучше убрать вообще и сделать как-то по-другому.
> https://github.com/Si0n/register3/blob/master/index.php#L13
> require './template/footer.php';
Это надо подключать из шаблона. Может нам понадобится нестандартный футер где-то, а не одинаковый для всех.
> https://github.com/Si0n/register3/blob/master/lib/list_action.php#L2
> include 'ini.php';
По моему у тебя этот файл подключается несколько раз. Сделай чтобы подключался только один раз, например в index.php.
> $db = new StudentsMapper($pdo);
То же самое. Можно создавать этот объект только один раз в ini.php, а не в нескольких местах.
> makeProtect( $_GET['search'] ) :
Эту функцию надо назвать лучше. «сделать защиту» не объясняет что она делает. Мне кажется, там должно использоваться слово вроде html, так как фактически это обертка над htmlspeialchars.
Более того, я думаю что эта функция тут вообще не нужна. Ты должен делать htmlspecialchars при выводе данных в шабоне, а не тут. Тут это не имеет никакого смысла, тут это скорее навредить может поиску, так как заменяет некоторые символы на последовательность вроде &
> https://github.com/Si0n/register3/blob/master/lib/functions.php#L8
> return makeProtect($_COOKIE[$name]);
Это неправильно. Экранировать данные надо там, где они используются, то есть в шаблоне. Функция getCookie должна просто возвращать точное значение куки и не пытаться заменять в ней символы. Ну сам подумай, как можно писать надежный код с функцией которая возвращает не точные, а измененные данные?
> if (count($data) == 0)
> $text = ' <br> Нет совпадений в базе студентов.';
HTML-теги должны быть в шаблоне, тут их быть не должно. Предупреждение должно выводиться только при неудачной попытке поиска, а если например база пустая то текст должен быть другой.
> https://github.com/Si0n/register3/blob/master/lib/paginator.php#L2
> require_once(__DIR__ . './functions.php');
Этот реквайр надо убрать и перенести в ini.php
> https://github.com/Si0n/register3/blob/master/lib/paginator.php#L4
> makeProtect( $_GET['p'] )
Тут уместнее использовать intval так как номер страницы должен быть числом
> $currentURL = '?search={search}&p={page}';
> $currentURL = str_replace('{search}', $search, $currentURL);
При подстановке данных в URL надо обрабатывать их через urlencode чтобы спецсимволы кодировались процентным кодированием ( https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Более того, в PHP есть стандартная функция для сборкии таких URL, она называется http_build_query, используй ее в таких случаях.
> https://github.com/Si0n/register3/blob/master/template/list.php#L22
> <td><?= $data[$k]['Surname'] ?></td>
Данные которые ты выводишь в шаблоне, должны быть экранироаны функцией htmlspecialchars для предотвращения XSS уязвимости и проблем с отображением спецсимволов вроде <. В имени конечно такие символы вряд ли встретятся, но проще экранировать все, чем разбираться что там может встретиться, а что нет.
Если что-то непонятно, или нужна подсказка, или хочешь посоветоваться, пиши.
И если не сложно, дай ссылок на решения других анонов, которые решали эту задачу в прошлых тредах
Сап, пыханы. Подскажите ньюфагу, как вы реализуете отправку почты с сайта? Есть какой-нибудь универсальный метод?
Для изучения MVC не нужны фреймворки. Если человек не понимает, он запихает логику в контроллер и представление, а где-гибудь в модели увидишь как в строку будут пихать html теги. А твой код игнайт протух.
Решаю задачку анона про айфон http://archive-ipq-co.narod.ru/l1/loops.html
Подскажите, почему у меня не выполняется условие, что если отстаток долга менее 5тр, то платеж равен ему.
ЧТо я делаю не так?
<?php
error_reporting(-1);
$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /
/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
\t
\t$creditBalance = ( $creditBalance $percent ) + $servicePayment - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
/ Если баланс отрицательный — хватит считать */
if ( $creditBalance <= 5000 && $creditBalance > 0) {
\t$mothlyPayment = $creditBalance;
}
elseif ( $creditBalance <= 0 ) {
echo "С меня хватит!\n";
\t break;
}
}
Решаю задачку анона про айфон http://archive-ipq-co.narod.ru/l1/loops.html
Подскажите, почему у меня не выполняется условие, что если отстаток долга менее 5тр, то платеж равен ему.
ЧТо я делаю не так?
<?php
error_reporting(-1);
$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /
/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
\t
\t$creditBalance = ( $creditBalance $percent ) + $servicePayment - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
/ Если баланс отрицательный — хватит считать */
if ( $creditBalance <= 5000 && $creditBalance > 0) {
\t$mothlyPayment = $creditBalance;
}
elseif ( $creditBalance <= 0 ) {
echo "С меня хватит!\n";
\t break;
}
}
Код выполняется сверху вниз. Соответственно нужно сначала сделать сумму платежа равной сумме оставшегося долга, а только потом платить. У тебя же все наоборот.
У нас аноны использовали:
— библиотеку getId3 для чтения информации о формате файла, кодках, разрешении и тд
— для аудио (и может быть видео) jQuery jPlayer
Если ты просто подключишь эти библиотеки то конечно ничему не научишься. Потому почитай еще про:
— HTML-теги audio и video
— что такое id3 теги: https://ru.wikipedia.org/wiki/ID3_(%D0%BC%D0%B5%D1%82%D0%B0%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5)
Также помни что браузеры поддерживают очень небольшй список аудио- и видеоформатов (+ они могут поддерживать дополнительные форматы если у пользователя установлены кодеки в ОС но я бы на это не рассчитывал). Вот он:
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
http://caniuse.com/#feat=webm
http://caniuse.com/#feat=mpeg4
https://helpx.adobe.com/flash/kb/supported-codecs-flash-player.html
Причем список форматов зависит от версии ОС, браузера, наличия кодеков. У флеша свой набор видео и флеш единственный способ играть видео в старых браузерах. Не забывай про наличие мобильных платформ.
Это значит что если ты хочешь как ютуб показывать любые загруженные видео, и чтобы это работало в максимальном числе браузеров, то ты должен пилить конвертер который будет преобразовывать видео в 2-3 максимально поддерживаемых формата (вроде H.264 и Vp8/9 для флеша) утилитами вроде ffmpeg или mencoder. Так как этот процесс длительный, его нельзя делать сразу в момент загрузку, то ты должен организовать очередь задач с использованием чего-то вроде Gearman и запускать демона который будет работать в фоновом режиме, брать из очереди задачи на перекодирование. Также, запуск внешней программы (ffmpeg) тоже непростая вещь. Ты должен собирать данные (логи) которые выводит программа, отслеживать наличие ошибок (а они будут). Удобно запускать внешние программы с помощью библиотек вроде Symfony Process Component, потому что руками писать аналогичную штуку — это минимум 300 строк непростого и неочевидного кода (я писал).
Это может выглядеть сложно, но ты должен все это понимать, чтобы если тебя например спросят «долго ли сделать аналог ютуба» не попасть впросак.
В этой задаче перекодировать видео не требуется, хотя если ты это хочешь сделать (в рамках файлообменника или отдельным проектом), я готов помочь подсказками.
>>490222
кодеигнайтер действительно старый
>>490382
Библиотеки вроде SwiftMailer поддержвают разные способы отправки, форматы писем, вложения и т д.
У нас аноны использовали:
— библиотеку getId3 для чтения информации о формате файла, кодках, разрешении и тд
— для аудио (и может быть видео) jQuery jPlayer
Если ты просто подключишь эти библиотеки то конечно ничему не научишься. Потому почитай еще про:
— HTML-теги audio и video
— что такое id3 теги: https://ru.wikipedia.org/wiki/ID3_(%D0%BC%D0%B5%D1%82%D0%B0%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5)
Также помни что браузеры поддерживают очень небольшй список аудио- и видеоформатов (+ они могут поддерживать дополнительные форматы если у пользователя установлены кодеки в ОС но я бы на это не рассчитывал). Вот он:
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
http://caniuse.com/#feat=webm
http://caniuse.com/#feat=mpeg4
https://helpx.adobe.com/flash/kb/supported-codecs-flash-player.html
Причем список форматов зависит от версии ОС, браузера, наличия кодеков. У флеша свой набор видео и флеш единственный способ играть видео в старых браузерах. Не забывай про наличие мобильных платформ.
Это значит что если ты хочешь как ютуб показывать любые загруженные видео, и чтобы это работало в максимальном числе браузеров, то ты должен пилить конвертер который будет преобразовывать видео в 2-3 максимально поддерживаемых формата (вроде H.264 и Vp8/9 для флеша) утилитами вроде ffmpeg или mencoder. Так как этот процесс длительный, его нельзя делать сразу в момент загрузку, то ты должен организовать очередь задач с использованием чего-то вроде Gearman и запускать демона который будет работать в фоновом режиме, брать из очереди задачи на перекодирование. Также, запуск внешней программы (ffmpeg) тоже непростая вещь. Ты должен собирать данные (логи) которые выводит программа, отслеживать наличие ошибок (а они будут). Удобно запускать внешние программы с помощью библиотек вроде Symfony Process Component, потому что руками писать аналогичную штуку — это минимум 300 строк непростого и неочевидного кода (я писал).
Это может выглядеть сложно, но ты должен все это понимать, чтобы если тебя например спросят «долго ли сделать аналог ютуба» не попасть впросак.
В этой задаче перекодировать видео не требуется, хотя если ты это хочешь сделать (в рамках файлообменника или отдельным проектом), я готов помочь подсказками.
>>490222
кодеигнайтер действительно старый
>>490382
Библиотеки вроде SwiftMailer поддержвают разные способы отправки, форматы писем, вложения и т д.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
Проблема в том что у тебя там стоит код
( $creditBalance $percent ) + $servicePayment - $monthlyPayment;
Где ты вычитаешь monthlyPayment (5000) сразу, а надо сначала проверить большой ли долг.
Спасибо.
Попробовал вот так, вообще все сломалось.
Что-то со мной не так.
<?php
error_reporting(-1);
$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /
for ($month = 1; $month <= 20; $month ++) {
$creditBalance = ( $creditBalance * $percent ) + $servicePayment;
if ( $creditBalance >= 5000 ) {
\t$creditBalance = $creditBalance - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\t\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
}
elseif ( $creditBalance <= 5000 && $creditBalance > 0) {
\t$mothlyPayment = $creditBalance;
\t$creditBalance = $creditBalance - $mothlyPayment;
}
{echo "С меня хватит!\n";
break;
}
}
Надо запихнуть команду в пхп код чтобы отображался результат этой команды. Делаю на линуксе. Хелп.
Можешь запостить код на ideone и дать ссылку? Вакаба съела звездочки в комментариях и код не запускается.
Ну и ты бы хоть написал, что значит «все сломалось», программа выводит ошибку (какую?), не тот ответ (какой?). А то непонятно даже что именно не так.
Спасибо оп, но пожалуй конвертер пилить мне пока рановато, я кроме сайта со студентами и доски объявлений не писал ничего.
Запуск внешних программ непростое дело и его надо делать правильно. То есть надо собирать данные которые выводит программа (для отладчки в случае ошибки), надо проверять код возврата. и тд. Надо делать таймаут на случай зависания программы. Удобно делать запуск через библиотеку вроде Symfony Process Component.
В сети ты можешь увидеть советы вроде использовать exec/passthru и подобные функции. Они по моему менее удобны и не фиксируют информацию об ошибках, не делают таймаута и тд.
но про ситуацию с поддерживаемыми форматами ты должен знать, так что поизучай таблички по ссылкам.
Посмотри внимательно на структуру ифа:
if ( ... ) {
код 1;
}
elseif ( ... ) {
код 2;
}
{
код 3;
}
Код 3 не относится к ифу, а находится в своем блоке. Это значит что он выполняется всегда. Ты наверно else удалил случайно.
Кстати если бы ты оформлял код правильно ( читай пост >>487140, это можно сделать автоматически пропустив код через phpformatter ) то ошибка была бы видна сразу. А так как у тебя скобки стоят как попало, ошибку трудно увилеть. Поэтому надо оформлять код правильно.
Спасибо огромное.
В общем, хотел попробовать поставить футaбy на сервер Сильно не бейте, я всего лишь учусь! Сделал все как по инструкции здесь %Ваш Абу вконец поехал, видимо, так как я не могу вставить ссылку, не пропускает спам лист%
Загрузил файлы, выставил права все как положено. И при обращении к файлу /imgbоаrd/imgbоаrd.php (предпоследний пункт инструкции) получаю ошибку
Warning: mysql_connect() [function.mysql-connect]: Access denied for user ' User-bla-bla-bla'@'12.3.4.56' (using password: YES) in /home/User-bla-bla-bla/public_html/imgboard/imgboard.php on line 26
MySQL connection failure
Глянув на строку 26 в imgbоаrd.php обнаруживаю там цикл:
if(!$con=mysql_connect(SQLHOST,SQLUSER,SQLPASS)){
echo S_SQLCONF;\t//unable to connect to DB (wrong user/pass?)
exit;
Параметры для mysql_connect берутся из файла config.php и содержат:
define(SQLHOST, 'localhost');\t\t//MySQL server address, usually localhost
define(SQLUSER, 'UserName');\t\t//MySQL user (must be changed)
define(SQLPASS, 'UserPassword');\t\t//MySQL user's password (must be changed)
Дело в том, то я поставил свои параметры, т.е. обозвал своего пользователя и поставил пароль. Но он пишет данную ошибку. Если я правильно все понимаю, то он не может дать мне права, так как я, видимо, не имею доступа. Файл лежит на хостинге. И, я так понимаю, мне нужно как-то создать пользователя sql или нет? Помогите, пожалуйста.
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/public_html/datatest.php on line 53
<?php
\tif(mysqli_num_rows($result_set)>0)
\t{
\t\twhile($row=mysqli_fetch_row($result_set))
\t\t{
\t\t\t?>
<tr>
<td><?php echo $row[1]; ?></td>
<td><?php echo $row[2]; ?></td>
<td><?php echo $row[3]; ?></td>
<!--<td align="center"><a href="index.php?delete_id=<?php echo $row[0]; ?>"><img src="b_drop.png" alt="Delete" /></a></td>-->
<td align="center"><a href="javascript:delete_id(<?php echo $row[0]; ?>)"><img src="b_drop.png" alt="Delete" /></a></td>
</tr>
<?php
\t\t}
\t}
\telse
\t{
\t\t?>
<tr>
<th colspan="4">There's No data found !!!</th>
</tr>
<?php
\t}
\t?>
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/public_html/datatest.php on line 53
<?php
\tif(mysqli_num_rows($result_set)>0)
\t{
\t\twhile($row=mysqli_fetch_row($result_set))
\t\t{
\t\t\t?>
<tr>
<td><?php echo $row[1]; ?></td>
<td><?php echo $row[2]; ?></td>
<td><?php echo $row[3]; ?></td>
<!--<td align="center"><a href="index.php?delete_id=<?php echo $row[0]; ?>"><img src="b_drop.png" alt="Delete" /></a></td>-->
<td align="center"><a href="javascript:delete_id(<?php echo $row[0]; ?>)"><img src="b_drop.png" alt="Delete" /></a></td>
</tr>
<?php
\t\t}
\t}
\telse
\t{
\t\t?>
<tr>
<th colspan="4">There's No data found !!!</th>
</tr>
<?php
\t}
\t?>
ссылка на гайд 1сhаn/futallаby/index_old.html
Ты должен на хостинге найти где-то в панели управления (или еще где-то) данные для соединения с MySQL и вписать их в конфиг. Там может быть не только пользоатель, пароль но и host другой, не localhost.
>>490445
Прежде чем исправлять ошибку мы должны кое-что сделать:
mysqli по умолчанию скрывает и не выводит никуда, даже в логи, ошибки пришедшие от базы (это неправильно, потому я всем советую использовать PDO). Например если ты написал неправильный SQL запрос mysqli ничего не скажет, просто вернет false и соответственно следующие функции будут возвращать ошибку (это так и есть в твоем случае) но первопричина ошибки останется неизвестной. Посмотри пример кода тут: http://php.net/manual/ru/mysqli.quickstart.statements.php
Ты видишь там if после каждой команды mysqli? Ты должен его писать каждй раз, чтобы при возникновении ошибки (например неправиьно написан запрос) ты мог вывести ее причну. Переделай свой код добавив if после каждой команды mysqli.
Только я не советую выводить детали ошибки пользователю, ему это видеть незачем, лучше бы выкидывать исключение например которое будет писаться в логи.
После того как ты это сделаешь, ты скорее всего увидишь текст ошибки и думаю тогда причина будет очевидна (если нет запости его сюда, я подскажу и переведу его). А сейчас ты не видишь подробностей ошибки и писать код в таком режиме по моему невозможно, каждая опечатка будет отнимать у тебя кучу времени.
Если твой учебник не рассказывает про этот if и обработку ошибок, выкидывай его. Это скорее всего старый учебник по функциям mysql где просто дописали букву i. Он неактуален и учит тебя плохим устаревшим подходам (это видно по коду), там наверняка и переменные прямо в запрос без плейсхолдеров вставляются.
Вот более-менее нормальная статья по mysqli: http://habrahabr.ru/post/141127/ (заметь что она рассказывает про обработку ошибок и плейсхолдеры; прочти ее).
Алсо, не стоит вывдить данные в HTMl без экранирования, можно получить уязвиость XSS, прочти статью https://github.com/codedokode/pasta/blob/master/security/xss.md
Хм. А всего-то стоило оп-пост почитать. Мило
Вот что нашел, получается, я вписываю в эти три поля MySql сервер -mysql.hostinger.ru, имя пользователя и пароль. И выдает ровно такую же ошибку.
>>490464
Да, создал нового пользователя и завелось. Но появилась новая проблема. При создании нового треда появляется вот такая гадость. Непонятно, почему не создается таблица, ведь там все вроде в порядке:
if (!table_exist(SQLLOG)) {
echo (SQLLOG.S_TCREATE);
$result = mysql_call("create table ".SQLLOG." (primary key(no),
no int not null auto_increment,
now text,
name text,
email text,
sub text,
com text,
host text,
pwd text,
ext text,
w int,
h int,
tim text,
time int,
md5 text,
fsize int,
root timestamp,
resto int)");
if(!$result){echo S_TCREATEF;}
}
TableBoard - название таблицы, которое он берет из config.php, а именно define(SQLLOG, 'CHANGEME');\t\t//Table (NOT DATABASE) used by image board
И, соответственно, он подклеивает название, вроде бы создает, но потом вот такая гадость.
>>490464
Да, создал нового пользователя и завелось. Но появилась новая проблема. При создании нового треда появляется вот такая гадость. Непонятно, почему не создается таблица, ведь там все вроде в порядке:
if (!table_exist(SQLLOG)) {
echo (SQLLOG.S_TCREATE);
$result = mysql_call("create table ".SQLLOG." (primary key(no),
no int not null auto_increment,
now text,
name text,
email text,
sub text,
com text,
host text,
pwd text,
ext text,
w int,
h int,
tim text,
time int,
md5 text,
fsize int,
root timestamp,
resto int)");
if(!$result){echo S_TCREATEF;}
}
TableBoard - название таблицы, которое он берет из config.php, а именно define(SQLLOG, 'CHANGEME');\t\t//Table (NOT DATABASE) used by image board
И, соответственно, он подклеивает название, вроде бы создает, но потом вот такая гадость.
Пофиксил. Спасибо за помощь, анончики!
var_dump($_SESSION) выводит всё содержимое переменной, но $_SESSION["username"]; при запихивании в другую, не запихивает ничего.
SESSION[Username] =array(1) { ["user"]=> object(loggedInUser)#3 (6) { ["email"]=> string(15) "defewgw@test.ru" ["hash_pw"]=> string(65) "e2ae8c6eb583d96310a97eaf63293599dabd9b53136bd5f0a9f39a2cfe376a83b" ["user_id"]=> int(3) ["title"]=> string(10) "New Member" ["displayname"]=> string(8) "testtest" ["username"]=> string(8) "testtest" } }
Ну молодец, что. Если будут какие-то вопросы, заходи к нам в тред.
>>487670
Для файлообменника Yii слишком мощный, и ты не сможешь использовать даже основные возмодности. Я советую делать на Yii либо test hub (учти это сложно: https://gist.github.com/codedokode/8733007 ) либо доску объявлений с категориями без регистрации.
>>488037
Про хеширование написано в вики (правда там формулы):
https://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
http://habrahabr.ru/post/219139/
https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%85%D0%B5%D1%88-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F
Хеширование бывает обычное и криптографическое, криптографичческое отличается тем что трудно сделать данные соответствующие хешу. Например имея криптографический хеш пароля, трудно его восстановить или подобрать другой пароль с таким же хешем.
> Эти все md5, sha1, crypt
Это криптографические хеши. sha1 длинее и новее. Crypt ( http://php.net/manual/ru/function.crypt.php ) вообще вызывает встроенную в систему функцию (которая в линуксе хеширует пароля) и она тут как я понимаю самая слабозащищенная так как старая.
В новом PHP есть стандартные функции для работы с паролями: http://habrahabr.ru/post/194972/
Также есть BCrypt который отличается тем что его долго вычислять и соответственно долго подбирать: https://ru.wikipedia.org/wiki/Bcrypt
Ну и вот мой урок про защиту паролей с примерами расчет стойкости к взлому: https://gist.github.com/codedokode/9576319
> Принцип работы этих алгоритмов,
Боюсь это тебе надо погуглить самому, я думаю, описание есть. Они основаны на перестановках и перемешивании битов большое число раз так, что исходные биты потом не восстановить. Ну и тебе придется вспомнить или изучить двоичную систему счисления и битовые операции вроде xor (это несложно) чтобы разобраться.
Статья про md5 довольно неплохая: https://ru.wikipedia.org/wiki/MD5
Битовые операции: https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%B8
> безопасность
безопасность зависит не столько от алгоритмов а от того как ты их применяешь. Часто уязвимости возникают именно из-за неправильного использования надежных функций. Ну например если ты не используешь соль то твои пароли можно вскрыть достаточно быстро (подробности в моем уроке поссылке выше).
Ну молодец, что. Если будут какие-то вопросы, заходи к нам в тред.
>>487670
Для файлообменника Yii слишком мощный, и ты не сможешь использовать даже основные возмодности. Я советую делать на Yii либо test hub (учти это сложно: https://gist.github.com/codedokode/8733007 ) либо доску объявлений с категориями без регистрации.
>>488037
Про хеширование написано в вики (правда там формулы):
https://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
http://habrahabr.ru/post/219139/
https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%85%D0%B5%D1%88-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F
Хеширование бывает обычное и криптографическое, криптографичческое отличается тем что трудно сделать данные соответствующие хешу. Например имея криптографический хеш пароля, трудно его восстановить или подобрать другой пароль с таким же хешем.
> Эти все md5, sha1, crypt
Это криптографические хеши. sha1 длинее и новее. Crypt ( http://php.net/manual/ru/function.crypt.php ) вообще вызывает встроенную в систему функцию (которая в линуксе хеширует пароля) и она тут как я понимаю самая слабозащищенная так как старая.
В новом PHP есть стандартные функции для работы с паролями: http://habrahabr.ru/post/194972/
Также есть BCrypt который отличается тем что его долго вычислять и соответственно долго подбирать: https://ru.wikipedia.org/wiki/Bcrypt
Ну и вот мой урок про защиту паролей с примерами расчет стойкости к взлому: https://gist.github.com/codedokode/9576319
> Принцип работы этих алгоритмов,
Боюсь это тебе надо погуглить самому, я думаю, описание есть. Они основаны на перестановках и перемешивании битов большое число раз так, что исходные биты потом не восстановить. Ну и тебе придется вспомнить или изучить двоичную систему счисления и битовые операции вроде xor (это несложно) чтобы разобраться.
Статья про md5 довольно неплохая: https://ru.wikipedia.org/wiki/MD5
Битовые операции: https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%B8
> безопасность
безопасность зависит не столько от алгоритмов а от того как ты их применяешь. Часто уязвимости возникают именно из-за неправильного использования надежных функций. Ну например если ты не используешь соль то твои пароли можно вскрыть достаточно быстро (подробности в моем уроке поссылке выше).
>Используй продвинутый ООП подход для решения задачи.
Что такое продвинутый ООП подход? Сам не нагуглил.
Молодец, все верно работает.
>>489607
Тебе надо сделать вывод ошибок от БД.
По умолчанию, если при работе с БД происходит ошибка, mysqli молчит как партизан и не выводит никаких предупреждений (а только возвращает false что мало помогает в поиске причины). Ты не узнаешь об ошибке и удивляешься почему ничего не работает.
Посмотри код в примерах: http://php.net/manual/ru/mysqli.quickstart.statements.php
Видишь, после каждого вызова функций mysqli стоит if с выводом сообщения об ошибке? То же самое надо сделать и тебе (а вот PDO кстати умеет сам выкидывать исключения и не трубет писать ифы). Только на реальном сайте ошибку лучше не показывать пользователю, а писать в логи или например выкидывать исключение.
Вот неплохая статья про mysqli и там тоже говорится про обработку ошибок: http://habrahabr.ru/post/141127/
После того как ты это сделаешь и увидишь причину ошибки, исправить ее будет наверно нетрудно.
>>489758
Жывотное! ЖЫР! Ты зделало координально неправильную вещь. Не красный а зеленый фломастер. Нет пробела,перед:запятой.
>>489636
В хроме на XP не работает часть https-сертификатов. В фаерфоксе работает больше, но тоже не все. Как можно было сломать существующую 20 лет технологию, я не понимаю.
>>489799
Так не нужны что есть несколько библиотек для их имитации + своя реализация в каждом втором фреймворке.
>>490138
То что ты сделал класс Article это правильное решение. Объекты — это хорошо.
> var articles = [
> article_1 = new Article ("Article 1", "10"),
не стоит совмещать создание массива и присваивание, лучше разнести это отдельно для читабельности. Ну и глобальные переменные не стоит создавать.
> if (localStorage.key(articles[a].name == articles[a].name)) {
Можешь объяснить кратко, что должна делать эта строка? Что делает это выражение:
> articles[a].name == articles[a].name
и вот это:
localStorage.key(...)
?
Также, я не советую исопльзовать 0 в качестве идентификатора товара так как его легко спутать с отстутсвием товара. Лучше идентификаторы начинать с единицы. Так как индексы в массиве начинаются с нуля, тебе надо будет вместо массива использовать словарь (хеш):
var articles = {
1: ...,
2:...
};
Также, советую освоить отладчик в браузере, им ты можешь пошагово выполнять программму и смотреть значения переменных: http://learn.javascript.ru/debugging-chrome
Отладчик это инструмент который может сберечь твое время на поиск проблемы.
И еще, не хочешь порешать наши задачки на JS (из оп поста)? Если есть время, советую порешать и постить сюда решения, так как пока я вижу у тебя есть пробелы в понимании. Ты явно пропустил часть важных вещей при изучении языка, тебе бы надо с самого начала все тщательно изучить по сайту вроде learn.javascript.ru (это наверно лучший русскоязычный сайт по теме).
>>489758
Жывотное! ЖЫР! Ты зделало координально неправильную вещь. Не красный а зеленый фломастер. Нет пробела,перед:запятой.
>>489636
В хроме на XP не работает часть https-сертификатов. В фаерфоксе работает больше, но тоже не все. Как можно было сломать существующую 20 лет технологию, я не понимаю.
>>489799
Так не нужны что есть несколько библиотек для их имитации + своя реализация в каждом втором фреймворке.
>>490138
То что ты сделал класс Article это правильное решение. Объекты — это хорошо.
> var articles = [
> article_1 = new Article ("Article 1", "10"),
не стоит совмещать создание массива и присваивание, лучше разнести это отдельно для читабельности. Ну и глобальные переменные не стоит создавать.
> if (localStorage.key(articles[a].name == articles[a].name)) {
Можешь объяснить кратко, что должна делать эта строка? Что делает это выражение:
> articles[a].name == articles[a].name
и вот это:
localStorage.key(...)
?
Также, я не советую исопльзовать 0 в качестве идентификатора товара так как его легко спутать с отстутсвием товара. Лучше идентификаторы начинать с единицы. Так как индексы в массиве начинаются с нуля, тебе надо будет вместо массива использовать словарь (хеш):
var articles = {
1: ...,
2:...
};
Также, советую освоить отладчик в браузере, им ты можешь пошагово выполнять программму и смотреть значения переменных: http://learn.javascript.ru/debugging-chrome
Отладчик это инструмент который может сберечь твое время на поиск проблемы.
И еще, не хочешь порешать наши задачки на JS (из оп поста)? Если есть время, советую порешать и постить сюда решения, так как пока я вижу у тебя есть пробелы в понимании. Ты явно пропустил часть важных вещей при изучении языка, тебе бы надо с самого начала все тщательно изучить по сайту вроде learn.javascript.ru (это наверно лучший русскоязычный сайт по теме).
И еще. Вот это неправильно:
> <a href="" onClick =
ссылка должна вести на какую-то страницу. Если у тебя она никуда не ведет, то это не ссылка, а кнопка и она должна делаться тегами <button type="button"> (рекомендуется) или span.
Я не знаю :( Но мне никогда такое делать не приходилось. Так что можно просто ответить «никак».
Ну еще можно конечно посмотреть Reflection, может там есть что-то для переопределения методов, или runkit, который и не такое умеет. Разумеется в коде такие вещи делать не стоит.
Для мимоанонов: финальный метод нельзя переопределить в наследнике, а от финального класса вообще нельзя наследоваться. Используется это очень редко: http://php.net/manual/ru/language.oop5.final.php
>>490180
Я не думаю что это правильный ответ так как у тебя другой класс, несовместимый с Foo:
function doSmth(Foo $foo) { ... }
$fake = new FooDecorator();
doSmth($fake); // Упс: Fatal Error: function doSmth expects instance of Foo class, FooDecorator given
Странно, мне Yii кажется довольно простым и понятным.
>>490288
Reflection наверно: http://php.net/manual/ru/book.reflection.php
Это класс который позволяет узнавать информацию о классах, методах, функциях и делать всякие вещи вроде залезания снаружи в приватные поля (доктрина так например данные из базы в объекты всовывает).
Лучше писать полностью с нуля (так ты получишь больше опыта и знаний, переписывание почти ничего не дает). У анона si0n ты код зря скопировал, там мы много чего переделаем. Также внимательно прочитай подробные комментарии к заданию. В этих комментариях очень много важной информации.
Ну и тебе лично такое замечание: надо сделать вместо одного файла index.php в корне несколько, для каждого действия вроде регистрации свой файл. И соответственно удалить switch из index.php. si0n пусть использует switch, а ты сделай по-другому.
То есть будет примерно так:
/lib/SomeClass.php
/lib/SomeOtherClass.php
/lib/config.php // параметры соединения с БД
/lib/init.php // файл инициализации который создает все нужные объекты и подключает нужные файлы
/views/ // шаблоны
/index.php // список студентов + поиск по ним
/profile.php // форма регистрации и редактирования данных
Также, ты используешь mysqli. Хорошо. Но надо сделать вывод ошибок из нее:
### Вывод ошибок в mysqli
По умолчанию, если при работе с БД происходит ошибка, mysqli молчит как партизан и не выводит никаких предупреждений (а только возвращает false что мало помогает в поиске причины). Ты не узнаешь об ошибке и удивляешься почему ничего не работает.
Посмотри код в примерах: http://php.net/manual/ru/mysqli.quickstart.statements.php
Видишь, после каждого вызова функций mysqli стоит if с выводом сообщения об ошибке? То же самое надо сделать и тебе (а вот PDO кстати умеет сам выкидывать исключения и не трубет писать ифы). Только на реальном сайте ошибку лучше не показывать пользователю, а писать в логи или например выкидывать исключение.
Вот неплохая статья про mysqli и там тоже говорится про обработку ошибок: http://habrahabr.ru/post/141127/
После того как ты это сделаешь и увидишь причину ошибки, исправить ее будет наверно нетрудно.
Также, ты возвращаешь из searchStudents массив данных. Чтобы не было как у других, сделай чтобы возвращался список студентов в виде массива объектов Student.
> switch ($sort) :
Версии с двоеточием используют в шаблонах, в коде используй фигурные скобки. break надо писать на отдельной строке. должен быть default выкидывающий исключение и помогающий тебе увидеть что передан неправильный параметр (вообще default должен быть в 99% случаев).
> $stud = $data->getStudent($user);
> $student = new Student($stud);
Преобразованием массива в объект должен заниматься маппер, это его задача, и он должен возвращать не глупый массив, а умный объект.
Про то как работает маппер написано в моем уроке: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Прочти его.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L14
Это неудобно. У тебя нельзя создать студента не передав кучу параметров. Убери это из конструктора и сделай отдельный метод например setAttributes который получает массив и проставляет значения свойств из него.
> https://github.com/V3N0m21/StudentList/blob/master/lib/register.php#L11
Проверка правильности должна быть в отдельной функции или классе (рекомендуется), а не длинной сплошной простыней кода. Вместо работы с массивом гораздо умнее в эту функцию передавать объект класса Student
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php
Данные надо экранирвать при выводе, прочти https://github.com/codedokode/pasta/blob/master/security/xss.md
Это те замечания, которые я увидел сразу. Там еще наверно будут потом другие.
Лучше писать полностью с нуля (так ты получишь больше опыта и знаний, переписывание почти ничего не дает). У анона si0n ты код зря скопировал, там мы много чего переделаем. Также внимательно прочитай подробные комментарии к заданию. В этих комментариях очень много важной информации.
Ну и тебе лично такое замечание: надо сделать вместо одного файла index.php в корне несколько, для каждого действия вроде регистрации свой файл. И соответственно удалить switch из index.php. si0n пусть использует switch, а ты сделай по-другому.
То есть будет примерно так:
/lib/SomeClass.php
/lib/SomeOtherClass.php
/lib/config.php // параметры соединения с БД
/lib/init.php // файл инициализации который создает все нужные объекты и подключает нужные файлы
/views/ // шаблоны
/index.php // список студентов + поиск по ним
/profile.php // форма регистрации и редактирования данных
Также, ты используешь mysqli. Хорошо. Но надо сделать вывод ошибок из нее:
### Вывод ошибок в mysqli
По умолчанию, если при работе с БД происходит ошибка, mysqli молчит как партизан и не выводит никаких предупреждений (а только возвращает false что мало помогает в поиске причины). Ты не узнаешь об ошибке и удивляешься почему ничего не работает.
Посмотри код в примерах: http://php.net/manual/ru/mysqli.quickstart.statements.php
Видишь, после каждого вызова функций mysqli стоит if с выводом сообщения об ошибке? То же самое надо сделать и тебе (а вот PDO кстати умеет сам выкидывать исключения и не трубет писать ифы). Только на реальном сайте ошибку лучше не показывать пользователю, а писать в логи или например выкидывать исключение.
Вот неплохая статья про mysqli и там тоже говорится про обработку ошибок: http://habrahabr.ru/post/141127/
После того как ты это сделаешь и увидишь причину ошибки, исправить ее будет наверно нетрудно.
Также, ты возвращаешь из searchStudents массив данных. Чтобы не было как у других, сделай чтобы возвращался список студентов в виде массива объектов Student.
> switch ($sort) :
Версии с двоеточием используют в шаблонах, в коде используй фигурные скобки. break надо писать на отдельной строке. должен быть default выкидывающий исключение и помогающий тебе увидеть что передан неправильный параметр (вообще default должен быть в 99% случаев).
> $stud = $data->getStudent($user);
> $student = new Student($stud);
Преобразованием массива в объект должен заниматься маппер, это его задача, и он должен возвращать не глупый массив, а умный объект.
Про то как работает маппер написано в моем уроке: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Прочти его.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L14
Это неудобно. У тебя нельзя создать студента не передав кучу параметров. Убери это из конструктора и сделай отдельный метод например setAttributes который получает массив и проставляет значения свойств из него.
> https://github.com/V3N0m21/StudentList/blob/master/lib/register.php#L11
Проверка правильности должна быть в отдельной функции или классе (рекомендуется), а не длинной сплошной простыней кода. Вместо работы с массивом гораздо умнее в эту функцию передавать объект класса Student
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php
Данные надо экранирвать при выводе, прочти https://github.com/codedokode/pasta/blob/master/security/xss.md
Это те замечания, которые я увидел сразу. Там еще наверно будут потом другие.
> `BirthDate` int(4) NOT NULL,
Надо использовать для года тип YEAR
> `GroupNumber` int(5) NOT NULL,
Номер группы лучше делать строкой. Иначе ты не можешь сохранить например 00010 не потеряв нули в начале.
> `pswrd` varchar(255) NOT NULL,
Лучше написать слово полностью, так как твое сокращение нестандартное и плохо запоминается. Также, у нас там по моему нет пароля и это лучше назвать по другому. Также надо добавить комментарий через COMMENT поясняющий что хранится в этом поле.
Если ты делаешь тестовых пользователей лучше всего давать им email вроде vasya@example.com или vaasya@mail.example.com. Домен example.com специально зарезервирован для примеров и логично его использовать. Это не надо исправлять, но учти на будущее.
Что именно? Ну и как я написал exec не лушее средство.
>>490447
Мимозамечание: в шаьлоне надо использовать if/while не со скобками а с двоеточием и endif/endwhile.
>>490657
> Как получать отдельные элементы от $_SESSION?
$a = $_SESSION['a'];
> но $_SESSION["username"]; при запихивании в другую, не запихивает ничего.
Покажи код.
>>490673
Я уже пару лет в /b не был. если кто-то вылезает, то это не я, но вообще это хорошя идея. Мне кажется надо периодически вылезать в /b, искать там прокрастинирующих/грустных анонов, заманивать в наш тред и давать им полезное занятие и может быть будущую профессию. Так что если кто-то хочет заниматься скаутингом в /b/ то я только это приветствую.
> почему ты такой аутист
никогда такой диагноз мне не ставили и вообще психических заболеваний у меня нет
>>490727
имитация классов на прототипах: https://learn.javascript.ru/classes
Ну и слово «продвинутый» думаю тут имеет смысл что ООп-подход более продвинутый в сравнении с процедурным.
а вообще эту задачу я когда-нибудь переделаю, к ней постоянно вопросы есть.
Что именно? Ну и как я написал exec не лушее средство.
>>490447
Мимозамечание: в шаьлоне надо использовать if/while не со скобками а с двоеточием и endif/endwhile.
>>490657
> Как получать отдельные элементы от $_SESSION?
$a = $_SESSION['a'];
> но $_SESSION["username"]; при запихивании в другую, не запихивает ничего.
Покажи код.
>>490673
Я уже пару лет в /b не был. если кто-то вылезает, то это не я, но вообще это хорошя идея. Мне кажется надо периодически вылезать в /b, искать там прокрастинирующих/грустных анонов, заманивать в наш тред и давать им полезное занятие и может быть будущую профессию. Так что если кто-то хочет заниматься скаутингом в /b/ то я только это приветствую.
> почему ты такой аутист
никогда такой диагноз мне не ставили и вообще психических заболеваний у меня нет
>>490727
имитация классов на прототипах: https://learn.javascript.ru/classes
Ну и слово «продвинутый» думаю тут имеет смысл что ООп-подход более продвинутый в сравнении с процедурным.
а вообще эту задачу я когда-нибудь переделаю, к ней постоянно вопросы есть.
Единственный выход - пиши паралельно.
>Покажи код.
Запихиваю это дело так же как в твоём примере. Что характерно, на домашнем сервере (просто запущенный денвер) это дело работает, а на хостинге отказывается.
>давать им полезное занятие
Это ты правильно заметил.
Труд сделал из быдла человека. "Труд" не в скотском советском смысле (каждый день от звонка до звонка на завод, как нибелунги-рабы кольца у Вагнера), и не как задротское средство самоутверждения ("азаза, 60-летняя Галина Павловна не может сама переустановить Шиндовс)))00, а я такой умный эникей-саморазвиванец" ), а как в некотором роде смысл самой человеческой жизни, получение радости от своего занятия как от игры, не знаю как выразиться.
Каждый способен что-то делать как минимум хорошо, дело только в психологическом настрое (пресловутая уверенность в себе), привычке к работе (да, этому тоже нужно учиться) и грамотному выбору профессии.
Встает извечный вопрос: кто виноват? Кто виноват, что тысячи талантливых людей маятся херней в таком отстойном месте как сосач?
Система образования, я считаю. Современные школы не выполняют... вообще никакой функции, максимум там идет формирование социальных навыков. И даже здесь процентов 10-15 проблемных детей не проходят этот животный отбор.
С самого детства должно идти выяснение способностей и наклонностей детей и прививание им любви к своему будущему занятию.
Иначе мы получаем тысячи офисных телефонных клерков, капчующих студентов-бездельников и несметное количество тупого, легко манипулируемого быдла.
Но что-то я увлекся.
Начал писать пост с целью выразить благодарность менторам сего треда, но по понятным причинам я не могу сказать спасибо прямо, тошнит от этих ваших телячьих-гомосячьих нежностей.
Пикрелейтед.
Так что, оп, ты делаешь важное дело, не слейся там. (Не дай бог я потеряю халявного репетитора)
>>490675
По делу. Я обязательно разберу досконально, как все эти фишки делаются нативными средствами php, но сейчас мне нужно в первую очередь учить фреймворки. Это в ДС-ах на собеседованиях задают дурацкие вопросы по теории. В мухосранске разговор короткий: покажите примеры своих работ (секретутка пересылает их по почте в Москву, там программист смотрит и выносит вердикт: годен/ не годен).
Поэтому буду делать на yii, пусть даже он и не совсем уместен для этой задачи.
Уже почти разобрал, осталась пара моментов.
Например, как передать переменные в макет? Не в шаблон, а во внешний layout, общий для многих контроллеров, но с переменными.
Допустим, у меня на сайте четыре области: хедер, футер, меню (сейчас модно заматывать его в тег nav) и область контента.
Понятно, что контент подгружаем из местного представления, подставляем в него переменные через метод render контроллера:
$this->render( 'view', array('posts' => $posts) );
Но как передать данные в меню? Шаблон меню общий для всех контроллеров, но в него должна передаваться переменная.
Допустим, у меня две страницы: фильмы и статьи. Соответственно в меню должны выводиться категории фильмов и статей. Они берутся из бд.
Как мне их передать в шаблон?
Пока не придумал ничего лучше, чем создать свойство или метод для каждого контроллера, которое будет возвращать этот список. Тогда можно обращаться к нему в представлении через this.
Правильный ли это подход?
Если переменных много, я рискую получить множество свойств контроллера. Причем их нужно прописывать для каждого контроллера... Хм, значит лучше наследовать от общего предка.
Блин, ну почему нельзя давать примеры? Почему я должен сидеть и изобретать колесо? Я понимаю, что так борются с веб-макаками, которые потом копипастят эти решения. Но уж совсем без примеров худо. На тебе сотни страниц теории, прочитай и пиши большой сайт. Ну офигеть теперь.
>давать им полезное занятие
Это ты правильно заметил.
Труд сделал из быдла человека. "Труд" не в скотском советском смысле (каждый день от звонка до звонка на завод, как нибелунги-рабы кольца у Вагнера), и не как задротское средство самоутверждения ("азаза, 60-летняя Галина Павловна не может сама переустановить Шиндовс)))00, а я такой умный эникей-саморазвиванец" ), а как в некотором роде смысл самой человеческой жизни, получение радости от своего занятия как от игры, не знаю как выразиться.
Каждый способен что-то делать как минимум хорошо, дело только в психологическом настрое (пресловутая уверенность в себе), привычке к работе (да, этому тоже нужно учиться) и грамотному выбору профессии.
Встает извечный вопрос: кто виноват? Кто виноват, что тысячи талантливых людей маятся херней в таком отстойном месте как сосач?
Система образования, я считаю. Современные школы не выполняют... вообще никакой функции, максимум там идет формирование социальных навыков. И даже здесь процентов 10-15 проблемных детей не проходят этот животный отбор.
С самого детства должно идти выяснение способностей и наклонностей детей и прививание им любви к своему будущему занятию.
Иначе мы получаем тысячи офисных телефонных клерков, капчующих студентов-бездельников и несметное количество тупого, легко манипулируемого быдла.
Но что-то я увлекся.
Начал писать пост с целью выразить благодарность менторам сего треда, но по понятным причинам я не могу сказать спасибо прямо, тошнит от этих ваших телячьих-гомосячьих нежностей.
Пикрелейтед.
Так что, оп, ты делаешь важное дело, не слейся там. (Не дай бог я потеряю халявного репетитора)
>>490675
По делу. Я обязательно разберу досконально, как все эти фишки делаются нативными средствами php, но сейчас мне нужно в первую очередь учить фреймворки. Это в ДС-ах на собеседованиях задают дурацкие вопросы по теории. В мухосранске разговор короткий: покажите примеры своих работ (секретутка пересылает их по почте в Москву, там программист смотрит и выносит вердикт: годен/ не годен).
Поэтому буду делать на yii, пусть даже он и не совсем уместен для этой задачи.
Уже почти разобрал, осталась пара моментов.
Например, как передать переменные в макет? Не в шаблон, а во внешний layout, общий для многих контроллеров, но с переменными.
Допустим, у меня на сайте четыре области: хедер, футер, меню (сейчас модно заматывать его в тег nav) и область контента.
Понятно, что контент подгружаем из местного представления, подставляем в него переменные через метод render контроллера:
$this->render( 'view', array('posts' => $posts) );
Но как передать данные в меню? Шаблон меню общий для всех контроллеров, но в него должна передаваться переменная.
Допустим, у меня две страницы: фильмы и статьи. Соответственно в меню должны выводиться категории фильмов и статей. Они берутся из бд.
Как мне их передать в шаблон?
Пока не придумал ничего лучше, чем создать свойство или метод для каждого контроллера, которое будет возвращать этот список. Тогда можно обращаться к нему в представлении через this.
Правильный ли это подход?
Если переменных много, я рискую получить множество свойств контроллера. Причем их нужно прописывать для каждого контроллера... Хм, значит лучше наследовать от общего предка.
Блин, ну почему нельзя давать примеры? Почему я должен сидеть и изобретать колесо? Я понимаю, что так борются с веб-макаками, которые потом копипастят эти решения. Но уж совсем без примеров худо. На тебе сотни страниц теории, прочитай и пиши большой сайт. Ну офигеть теперь.
Смотри логи либо включи отображение ошибок (это на своем компьютере, на хостинге надо смотреть логи). Код вряд ли просто так не работает, просто у тебя выключен вывод ошибок.
Что ты хочешь услышать? Подбадривание?
Да, ты будешь путаться, если 7-8 дней учишь яваскрипт (и, дай угадаю, 15-16 дней php).
Я тоже немного путался первые месяцы. Ничего, через полгода прошло.
>уже вникаю понемногу в саму суть языка
Эта наивность умиляет. js при внешней простоте достаточно сложный язык.
Яваскрипт нужно знать очень сильно, почти также хорошо как php.
А также sql, css и еще охулиард мелких несистематизированных знаний.
> Это в ДС-ах на собеседованиях задают дурацкие вопросы по теории.
Ну подумай сам, для других профессий люди по много лет учатся, наверно и для программирования надо немного с теорией повозиться. А не спешить, пропуская темы, это ни к чему хорошему не приведет. К нам в тред иногда заходят такие аноны-торопыги и код у них часто очень ужасный. Люди пропускают изучение основ и потом жалуются что все сложно, что ничего не понятно.
Соответственно не умея например правильно работать с формами на чистом php, ты вряд ли будешь хорошо c ними работать с использованием фреймворка.
Ты прочел документацию по Юи? Именно документацию, а не уроки на левых сайтах? Если нет, то начни с прочтения.
Также, можно искать ответы в коде фреймворка, в гугле и задавать вопросы в нашем треде. Как видишь, имеется богатый выбор.
> Пока не придумал ничего лучше, чем создать свойство или метод для каждого контроллера, которое будет возвращать этот список. Тогда можно обращаться к нему в представлении через this.
Копипастить это свойство неправильно. Копипастить вообще неправильно. Как минимум надо поместить его в базовый контроллер от которого наследуются остальные (а если такого нет то сделать его). Ну и свойство это плохо (где гарантия что оно задано?), лучше сделать метод вроде getMovieCategories()
Я тут погуглил, действительно, похоже что единственный адекватный способ это сделать метод в базовом контроллере.
> Блин, ну почему нельзя давать примеры? Почему я должен сидеть и изобретать колесо?
Ты не прав. Если ты понимаешь как работает фреймворк то тебе не нужны никакие примеры, ты сам можешь что угодно написать. Если не понимаешь, то надо его изучать, гуглить ит.д.
В случае с меню, я согласен, что для начинающего это неочевидно. Но документация намного важнее и ценнее чем примеры. Какая польза от примеров если непонятно как они работают? Ну и каждому человеку нужен свой пример кода, тебе нужно меню а кому-то другому что-то другое, в итоге надо тысячи разных примеров.
У нас в ОП-посте есть задания на JS, хорошо бы пройти большую часть + DOM + jquery.
>>490774
Не знаю, я не читал эту книгу. Обычно советуют не заучивать какие-то сложные вещи, а попытаться понять логику за ними, то есть разобраться как алгоритм получается, как можно к нему придти, почему сделано так, а не иначе, тогда будет проще.
Ну я по названию алгоритма догадался, например, о чем речь, но меня больше волнует к-во материала.
>Ты прочел документацию по Юи?
Разобрал api базовых классов, что и как они делают, получил общее впечатление.
Сделал несколько сот хелловордлов для закрепления.
Если ты о так называемом руководстве, то это какой-то бессистемный кусок собачьего кала. Тут >>487656 ты даже частично согласился со нмой.
Мне было легче разбираться по коду тех демок, что идут в комплекте, и api.
>>490784
>Ты не прав.
Прав. Иначе в вузах не было бы лабораторных и практических занятий.
Прослушал 200 часов лекций по высшей математике или сопромату? Молоца! Приходи на экзамен, только попробуй сука не решить эти дифференциальные уравнения третьего порядка. Что, простите? А мне по-барабану, что ты никогда в жизни их не решал, вон я тебе двести часов лекций прочитал рисовал всякие формулы Лейбница.
Впрочем, не обращай внимания. Я давно не ебался, поэтому у меня плохое настроение. А у тебя как дела на половом фронте?
>>490787
900 страниц его пугают. Шел бы ты отсюда, мальчик.
Ты охуеешь, насколько больше нужно перечитать, чтобы стать грамотным программистом.
Я тут по две-три сотни страниц в день листаю всякого дерьма из гугла, видишь как горит моя жопа?
Не опускай до уровня долбоёба из б. Они не пугают, вопрос, как правильно их прочитать и как выбрать главное.
Возьми любую книгу по математике хотя бы Винберга того же и один день прочти 100 страниц решая задачи. Ты поедешь где-то на 40, а все потому, что читая по 40 страниц в день можно освоить програму за 4 года в 2. Ну да ладно, спор это бессмысленный.
Подсказка, ты дерьмо не листай.
Я выше уточнил. Как выбрать главное, бака? Ты совсем не читаешь?
Вопрос по ZF2 там в туториале класс модели создается с публичными полями, а это разве не нарушает принципов ООП? Я так понимаю, что мне стоит их сделать приватными?
нужно связь многие к многим, установить какое-то ограничение не больше 3 или 4 категорий, или как?
Скорее ты просто не поняло того, что имел ввиду Кормен. :з
Ты можешь гугл покорить и стать Джеффом Дином так и не решив оттуда все задачи.
А выбрать то, что тебе надо, очевидно же!
Книгу достаточно пролистать чтобы знать какие есть алгоритмы и когда их лучше применять, а дальше уже писать код и применять их по мере необходимости. Иначе пользы от абстрактного знания алгоритмов которые ты не применяешь не будет. Это всё очень быстро забывается, но знать что такие-то там есть - вот это полезно.
А так:
1) пару сортировок, пузырек там и другие
2) бинарный поиск
3) работу с деревьями
4) уметь в гугл чтобы найти необходимый алгоритма за o(n) в Интернете
Для практики можешь порешать задачки олимпиадного программирования:
topcoder, codeforces, codility
Тогда спасибо, но это не совсем пхп, это ведь ООП
> там в туториале класс модели создается с публичными полями
Ты уверен что там именно публичные поля а не их имитация через магические методы вроде _ _ get ? http://php.net/manual/ru/language.oop5.overloading.php#object.get
В зенде такое много где встречается.
> это разве не нарушает принципов ООП?
Не совсем. Я думаю, ты иимеешь в виду инкапсуляцию, в этом плане да, использоать приватные поля с геттерами-сеттерами лучше, чем публичные, но для очень простых случаев и маленьких приложений можно и публичные поля сделать.
Преимущество инкапсуляции в том, что когда ты например захочешь проверять присваиваеме значения, тебе надо сделать это в одном методе-сеттере, а в случае с публичными полями искать по всему коду места где идет доступ, неудобно. Потому мне кажется что с приватными полями будет удобнее работать.
Насчет алгоритмов, тот анон прав, надо бы знать хотя бы сортировки, бинарный поиск, деревья, списки, графы, поиск в ширину/глубину, хеш-таблицы, может быть префксные деревья. Наизусть учить алгоритмы не надо (например балансировку черно-красных деревьев я не помню), но представлять чем отличаются разные структуры данных и какая для чего подходит, надо бы.
slim/slim suggests installing ext-mcrypt (Required for HTTP cookie encryption)
Это пригодится в задании на файлообменник (и в других проектах), или проигнорировать?
Ну я вполне готов, я у мамы раньте так что на еду деньги есть и я никуда не тороплюсь.
Не работает у меня даже этот сраный хелловорлд:
The requested URL /slim/hello/:world was not found on this server.
Что я не так делаю?
1) В виртуальном хосте home создал директорию slim. То есть полный адреc к стартовому скрипту (или как это называется)
http://home/slim/index.php
2) В директории slim установил фреймворк через композер
php composer.phar install slim/slim
3) В index.php добавил автозагрузку
require 'vendor/autoload.php';
4) И написал демо-пример
$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Что мне теперь в урле писать-то, чтобы заработало?
Пробовал
home/slim/hello/world
home/slim/hello/:world
home/slim/index.php?r=hello/world
Ничего не работает (404), даже на главной home/slim/index.php 404 статус.
Нужно в корне сайта (в папке yoba.com) создать файл .htaccess и в нем прописать редирект (перенаправление с одной страницы на другую).
https://masterhost.ru/support/doc/apache
https://beget.ru/articles/htaccess
А файл htaccess положил? Он перенаправляет все запроы на index.php а без него Апач пытается найти папку hello, а в ней файл world, отсюда 404
Доки: http://docs.slimframework.com/routing/rewrite/
Описание mod_rewrite: http://habrahabr.ru/company/sprinthost/blog/129560/
Ты далеко не первый анон, кто с этим столкнулся, надо будет написать автору Слима или что лучше, сделать пулл-реквест в докуентацию. Есть желающие улучшить документацию опен-сурс проекта и дописать пару абзацев на английском в гайд?
Сначала мы придумываем себе проблемы, а потом героически превозмогаем. Зачем вообще делать мигарцию если все прекрасно работает на MySQL?
Ну и фанатизм виден в каждом абзаце: то, что какой-то программист-неуч хранит даты в виде числа в BIGINT подается как недостаток MySQL (как будто то же самое невозможно в Postgres). То, что в MySQL есть блокировки которых нет в Postgres, внезапно тоже оказывается недостатком. Наличие возможности это недостаток!
Справедливости ради, то что в MySQL по умолчанию строгий режим отключен, это действительно нехорошо. Но ведь никто не мешает его включить и исправить найденные баги, это проще чем переезжать на другой движок. И я всем анонам советую использовать строгий режим.
Я не считаю что Postgres плохой движок. В нем много интересных фич (хотя я бы предпочел особо ими не увлекаться), но переносить на нее нормально работающее приложение глупо. Ты потратишь кучу времени и сил, и не получишь никакой прибыли с этого. Лучше потратить это время на добавление новых фич, которые могут принести пользу.
Скопипастил .htaccess вида
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
Hello world заработал, главная страница сайта - нет.
Может, неправильный htaccess? (все никак не найду время разобраться в его настройках, видно придется не откладывать, а заняться сейчас)
>дописать пару абзацев на английском в гайд
Я не могу, плохо знаю английский и не знаком с фреймворком.
Возвращаясь к теме вывода переменной в глобальный шаблон во фреймворке YII.
ОКАЗЫВАЕТСЯ есть специальный виджет для этих целей:
http://www.yiiframework.com/doc/api/1.1/CClipWidget
Только вот почему мне пришлось потратить два дня и пролистать от корки до корки весь api, чтобы найти такую простую информацию?
Ну ладно, зато теперь я знаю вообще обо всех возможностях, и в случае чаво уже буду знать, где искать.
Но мне такой подход откровенно не нравится. Хоть бы оглавление сделали, елки зеленые.
Автор по моему толком в ней не разобрался сам.
> Вот только сериализация сущностей в Doctrine довольно каверзна и может привести с серьёзным проблемам.
Надо отсоединять (detach) сущность при добавлении в сессию и присоединять при сохранении изменений в базу. Да, там есть кавыерзные моменты, но это хороший повод задуматься, а нужно ли нам хранить сущности в сессии? Если ты хочешь хранить в сессии залогиненного юзера, то остановись и подумай, не логичнее ли хранить только его id и не дублировать данные которые и так есть в БД?
> Java приложение живёт намного дольше, чем PHP запрос.
И это делает реализацию ORM еще сложнее так как долгоживующие объекты синхронизировать с базой сложнее и больше шанс где-то разойтись. А в PHP все проще.
> Identity Map бесполезна в окружении «без сохранения состояния»
Чушь.
> Если ваш код хорошо структурирован, то вам и не понадобится дважды запрашивать одну и ту же сущность.
Только если это хелло ворлд из 10 строчек. Реальные приложения, особенно которые развиваются долгое время, очень сложны.
> В окружении «без сохранения состояния», «ленивая» загрузка является плохой практикой.
Автор явно не писал ничего сложнее блога
> За исключением редких случаев (логирование, обновление времени последнего коннекта и проч.), нам просто нужно изменить данные по POST запросу. После чего мы незамедлительно редиректим пользователя на другую страницу.
Автор мыслит блогом. То, что мы можем захотеть загрузить много сущностей и как-то хитро их обработать, он не подумал.
Вот смотрите, человек который толком не знает ни php ни doctrine пишет статью как все плохо и такие же не понимющие люди ее плюсуют, твитят и репостят. Я напишу умную мысль и никто кроме трех с половиной анонов не прочтет. Где тут логика?
Мне кажется, он не для этого, он для другого. Он для того чтобы один раз отрендерить какую-то штуку, запомнить HTML и потом вставить ее в нескольких местах на странице (это написано в документации). Соответственно для твоей задачи он вряд ли подходит.
Как я написал, гораздо проще вызывать метод контроллера из лейаута через $this->doSmth()
Чтобы на PHP писать как на джаве (а не быдлокодить) надо много учиться. Так что я бы подумал, а стоит ли оно того. Но с другой стороны PHP конечно проще.
Не знаю, во всяком случае в этих целях его используют.
http://www.yiiframework.com/wiki/127/dynamic-sidebar-using-cclipwidget/
Оказывается, кроме убогого оф.руководства и исходников api, есть еще бложик wiki.
Надо же. Жаль, что только сейчас на него наткнулся.
> Most applications will have one or two sidebars and often you want to control the content that should appear in the sidebar based on the action.
как я понимаю, это не твой случай. Ну и если тебе надо менять сайдбар в зависимости от текущей страницы то проще всего его сделать виджетом и передавать ему нужные параметры.
Кстати! А ты не можешь сделать меню виджетом? У виджета свой шаблон, он может лезть в базу и тд., его можно подключать в любом месте. Хотя не знаю, наверно это усложнение и проще все же сделать метод в контроллере.
>лезть в базу из представления
Да ну, это же нарушает mvc. Я как раз и морочусь, чтобы не было подобных ситуаций.
>control the content that should appear in the sidebar based on the action
У меня меню изменяется не в зависимости от экшена, так в зависимости от контроллера. Какая разница? По-моему, тоже подходит.
>У виджета свой шаблон, он может лезть в базу
Насчет "лезть в базу" это как-то не по mvc-шному.
Ну хорошо, мы имеем уже получается 2-3 решения этой проблемы. Мне лично как-то больше по душе вариант с клипсами, только что погуглил, все их используют для этого, а миллионы не могут ошибаться.
Лучше подскажи, почему у меня не до конца работает slim?
Как я говорил выше >>490973 , после добавления .htaccess пример на hello world заработал, но главная страница почему-то 404.
Виджет ведь это по сути маленький контроллер, потому он может вызвать модель, получить данные и передать их своему представлению для отрисовки. Или в Юи не так? В документации не сказано ничего про модели.
> Какая разница? По-моему, тоже подходит.
Ну сделай, но по моему это будет недобно. Тебе надо где-то (где?) передавать данные для меню, где-то рендерить меню, потом его выводить в лейауте. Я не понимаю, чем это удобнее чем прямолинейный код вроде
<?php foreach ($this->getCategories() as $categ): ?>
<?= $categ->getName() ?>
<?php endforeach ?>
Вообще, эти сложности из-за системы используемых лейаутов. Потом когда-нибудь ты изуишь twig и наледование шаблонов и уивдишь что есть и другие рещения проблемы «как вывести шапку/футер/меню на каждой странице».
> а миллионы не могут ошибаться.
ох лол
> после добавления .htaccess пример на hello world заработал, но главная страница почему-то 404.
Это 404 от слима или от Апача? Ты в index.php прописал действие которое надо делать при открытии главной страницы? Если нет то логично что он показывает 404.
▲ ▲
▲ ▲
▲ ▲
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
▲ ▲
▲ ▲
▲ ▲
▲ ▲ ▲ ▲ ▲ ▲
До этого такой режим был в сафари, вконтакте, в виде расширений к браузерам.
Я советую вам облегчить жизнь своим пользователям и изначально делать сайт в таком стиле (inb4: заказчик настаивает — речь о тех случаях когда у вас есть голос).
Кстати в старой Опере не было такого, но была возможность отключить CSS и получалось что-то аналогичное (но конечно не такое красивое). Я ей пользовался на сайтах где шрифт мелкий или где белые буквы на черном фоне, которые тяжело читать.
Я хочу узнать на каком количестве знаний яваскрипт для попадания на работу можно остановится.
class Album
{
public $id;
public $artist;
public $title;
etc
}
Да. Спасибо. Мне с прикладной когда-то сказали, что я проектирую, как первокурсник мех-мата, с тех пор, я все это исправляю.
Советуешь еще что нибудь почитать кроме introduction? Я их, кстати реализовывать буду на python скорее всего, удобно и читабельно
И еще, мне никто не ответил по поводу категорий.
Как лучше их делать? Можно ли их всех перечислять в одном поле, или не стоит?
то есть вот так делать
Записи
1запись
2ид категорий 1, 2, 3
категории
1 Новости
2 Новости1
3 новости!111
В йии [yi:] (такая транскрипция на оф.сайте http://yiiframework.ru/doc/guide/ru/quickstart.what-is-yii)
виджеты выполняют роль хелперов, например
CHtml::endForm()
выполняет следующий сверхмощный код
public static function endForm()
{
return '</form>';
}
CHtml::form() чуть сложнее, потому что нужно разобрать html-атрибуты.
Но он тоже возвращает голый html.
Виджеты типа ClistView, которые выводят в цикле записи из БД, тоже фактически являются надстройкой над foreach.
Так что насколько я успел понять, в Yii виджеты выполняют роль хелперов для формирования html, не более. Впрочем, я еще плохо разбираюсь, недавно начал изучать фреймворк.
Виджет CMenu, специально предназначенный для вывода меню, принимает массив и тупо выводит его в цикле:
$this->widget('zii.widgets.CMenu', array(
'items'=>$array,
));
Проблема только в том, чтобы передать туда эти данные. Если виджет находится в области контента, это делается через метод render() внутри action контроллера:
$this->render('viewName', array('variableName'=>$var1, 'var2'=>$var2 ....));
Как передать данные в область скажем хедера или футера мы вроде бы тоже решили минимум двумя способами (через доп.методы родительского контроллера, которые потом придется переопределять в наследниках) и через клипсы, то есть этакое "запекание" контента.
>эти сложности из-за системы используемых лейаутов
Вот и я так думаю. Нет чтобы описать в оф.руководстве подобные моменты, они там пишут какую-то очевидную хрень, типа куда клацать в гинираторе кода, шоб он создал нам файлик модели.
>Это 404 от слима или от Апача? Ты в index.php прописал действие
От слима. Не имею представления, как..
А, ну да. Добавил заглушку типа
$app->get('/', function(){});
заработало.
Непонятно, что со всем этим делать дальше, ну да ладно. Сейчас остужусь, может наступит просветление.
В йии [yi:] (такая транскрипция на оф.сайте http://yiiframework.ru/doc/guide/ru/quickstart.what-is-yii)
виджеты выполняют роль хелперов, например
CHtml::endForm()
выполняет следующий сверхмощный код
public static function endForm()
{
return '</form>';
}
CHtml::form() чуть сложнее, потому что нужно разобрать html-атрибуты.
Но он тоже возвращает голый html.
Виджеты типа ClistView, которые выводят в цикле записи из БД, тоже фактически являются надстройкой над foreach.
Так что насколько я успел понять, в Yii виджеты выполняют роль хелперов для формирования html, не более. Впрочем, я еще плохо разбираюсь, недавно начал изучать фреймворк.
Виджет CMenu, специально предназначенный для вывода меню, принимает массив и тупо выводит его в цикле:
$this->widget('zii.widgets.CMenu', array(
'items'=>$array,
));
Проблема только в том, чтобы передать туда эти данные. Если виджет находится в области контента, это делается через метод render() внутри action контроллера:
$this->render('viewName', array('variableName'=>$var1, 'var2'=>$var2 ....));
Как передать данные в область скажем хедера или футера мы вроде бы тоже решили минимум двумя способами (через доп.методы родительского контроллера, которые потом придется переопределять в наследниках) и через клипсы, то есть этакое "запекание" контента.
>эти сложности из-за системы используемых лейаутов
Вот и я так думаю. Нет чтобы описать в оф.руководстве подобные моменты, они там пишут какую-то очевидную хрень, типа куда клацать в гинираторе кода, шоб он создал нам файлик модели.
>Это 404 от слима или от Апача? Ты в index.php прописал действие
От слима. Не имею представления, как..
А, ну да. Добавил заглушку типа
$app->get('/', function(){});
заработало.
Непонятно, что со всем этим делать дальше, ну да ладно. Сейчас остужусь, может наступит просветление.
Связь многие-ко-многим реализуется через таблицу связи с 2 внешними ключами.
Ограничение на число категорий делай на стороне PHP.
Алсо прочти про нормализацию прежде чем проектировать базы данных. Это не сложно, но поможет избежать многих ошибок.
http://i-novice.net/6-normalnyx-form-bd/
http://habrahabr.ru/post/193756/
http://www.google.ru/search?aq=0&oq=yjhvfkbpfwbz+%2Cl&sourceid=chrome&ie=UTF-8&q=%D0%BD%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F+%D0%B1%D0%B4
>то есть вот так делать
У тебя оба примера не соответствуют нормальным формам, в первой атрибут «категории» не атомарный, во второй дублирование данных.
Я уже нагуглил, мне просто иногда очень лень гуглить, но вот в чем дело. Я читал, когда на собеседования ходил и потому расспрашивал, зная, что пихать в одну строку несколько различных данных плохо
Разные места, разные требования.
Как тебе ответить о "количестве знаний"? В процентах или тугриках?
Скажем, нужно знать от 50 до 100 процентов материала этого простого учебника learn.javascript.ru
Там в конце каждой главы есть упражнения (даже с решениями), можно себя проверить.
Решил сделать, чтобы при возвращении студентов возвращало их не в виде массива данных, а в виде экземпляров объекта Student
https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L87
, и тут же столкнулся вот с этим:
https://github.com/Si0n/register3/blob/master/template/list.php#L19
Ничего не выводит, я проверял весь массив объектов - он не пустой и в нем находятся именно объекты, но методы не работают почему-то.
Это точно массив объектов? Не увидел откуда они туда попадают. Писанину глянул мельком, могу быть не прав.
https://github.com/Si0n/register3/blob/master/lib/list_action.php#L16
https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L75
Оттуда и попадают по идее (через поиск должно вернуть массив из 2 экземпляров), я проверял $students через var_dump, в нем как и должно 2 объекта находится с протектед свойствами.
Вот я и говорю. Что не вижу объекты. Вижу просто массив со всякими данными.
Массив не объект, и он не обладает методами.
Ты должен создать объект Student. Делается это так.
$student = new Student('сюда конструктором запихаешь разные данные');
и уже у обекта $student можно запускать его методы.
$student->getName()
$student->getSurname()
$student->getSex() и т.д.
Суть такова, перекатываюсь с тестирование в пхп. В хтмл и цсс давно нормально могу. Вот решил взятся за php.
Прошел курсы на кодакадеми и мне подкинули такое задание.
Нужно сделать бложик в котором.
1. Список записей. Название и кусок записи.
2. Открытие записи.
3. Логин и добавление записи.
Собственно вопросы:
1. где можно посмотреть нормальные примеры кода вот таких вот простых блогов найти.
2. Не могу понять как работать с бд. Что ставить что бы работать c mysql, создавать в ней нормально таблицы и все такое. С запросами я еще понял
Ну я же через параметр fetchall $stud = $srchStudents->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "student");
возвращаю по идее не просто массив данных, а массив объектов. https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L87
Имена полей в базе совпадают с именами полей объекта с точностью до регистра букв?
Алсо тебе не обязательно использовать FETCH_CLASS, ты можешь взять из базы массив массивов и в цикле сделать из них массив объектов.
>>491192
У него PDO::FETCH_CLASS
>>491194
Кодеакадеми это очень базовый уровень и с ними может еще рановато делать сайты.
> где можно посмотреть нормальные примеры кода вот таких вот простых блогов найти.
У нас в оп посте есть годные задачи на список студентов и файлообменник но чтобы их решать возможно тебе надо пройти еще наш (или не наш) учебник объясняющий про ООП.
Посмтри задачу на список студентов например, к ней очень подробные комментарии про ее решение, про MVC, про формы, ты мало где найдешь эту информацию.
Чтобы работать с базой надо изучить SQL, посмотри наши задачки на SQL в оп посте, там же есть ссылки на туториалы.
>Имена полей в базе совпадают с именами полей объекта с точностью до регистра букв?
О, кажется в этом проблема, спасибо
Потому что получаются абзацы без отступов, текст сплошной простыней, списки без точек и отступов, часть заголовков без отступов, таблицы без паддингов где текст еле помещается в ячейки и выглядит это отвратительно.
Ты модешь сказать, я восстановлю все сброшенные стили. А я скажу что 95% верстальщиков ничего не восстанавливает, и какой смысл восстанавливать если можно просто не ломать?
Надо знать и умело использовать дефолтные стили в браузерах а не пытаться с ними бороться.
В общем для меня reset синоним слова быдловерстка.
Если тебе еще интересно что я причисляю к быдловерстке, то это:
— <a href=""
— <a href="#"
— <a href="javascript:void"
— использование overflow вместо clearfix
— испльзование overflow hidden там где это не надо (в 95% случаев не надо)
— кастомные скроллбары
— тормозящие при прокрутке страницы
Если тебе интересно, какой дизайн мне нравится, то это черные буквы на белом фоне, как например на medium.
В случае с урлами гет-запроса все понятно
$app->get('/posts/:id', function($id){
// показать книгу с указанным айди
});
То что происходит с постом? Чо это такое:
$app->post('/books', function(){
// создать новую книгу
});
http://docs.slimframework.com/routing/post/
/books это адрес, с которого пришел запрос постом?
девелоперы востребованы в качествен не верстальщиков или такое можно только выше джуниора?
даже пост коряво оформил, говорю же
О, хтмл-наци, иди сюда.
Я вот как раз сейчас пишу форму. Что совать в атрибут action, если обработчик в этом же файле?
action="" я так понял тоже не кошерно.
SCRIPT_NAME пойдет?
А на джаве ты сразу будешь писать идеальный код? Какие же вы блядь тупые, вам прежде чем кодить нужно что-нибудь по логике почитать.
Где я проебал?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> First</title>
<link rel="stylesheet" href="css/bootstrap.css" type="text/css"/>
</head>
<body>
<?php $act = isset($_GET['act']) ? $_GET['act'] : 'list'; ?>
<?php switch ($act) {
case 'list':
require('templates/list.php');
break;
case 'view-entry':
require('templates/entry.php');
break;
}
?>
</body>
</html>
Где я проебал?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> First</title>
<link rel="stylesheet" href="css/bootstrap.css" type="text/css"/>
</head>
<body>
<?php $act = isset($_GET['act']) ? $_GET['act'] : 'list'; ?>
<?php switch ($act) {
case 'list':
require('templates/list.php');
break;
case 'view-entry':
require('templates/entry.php');
break;
}
?>
</body>
</html>
Я не понял вопроса.
>делал в index.php решил вот перевести в index.html
Ты хочешь переименовать файл с расширением php в html?
Зачем? Php в html-файлах по умолчанию не выполняется.
Апач думает, что там голый html и сразу отдает браузеру, минуя интерпретатор.
По моему тебе стоит для начала вспомнить что указано в HTTP запросе. Когда ты открываешь страниц или отправляешь форму, браузер отправляет HTTP запрос и в его первой строке указаны:
— протокол
— метод (GET/POST/HEAD и другие)
— URL
https://ru.wikipedia.org/wiki/HTTP#.D0.A1.D1.82.D0.B0.D1.80.D1.82.D0.BE.D0.B2.D0.B0.D1.8F_.D1.81.D1.82.D1.80.D0.BE.D0.BA.D0.B0
$app->post('/books' ... ) задает обработчик, который будет вызван при отправке POST запроса на URL /books
$app->get соответственно для метода GET
> /books это адрес, с которого пришел запрос постом?
Не с которого а на который. Обычно через POST отправляют формы так что это URL на который отправлена форма.
Можно. Но HTML/CSS знать надо чтобы не набыдлокодить когда тебе например надо будет вывести новости в 2 колонки вместо одной или передвинуть меню вправо (у нас есть хорошие задачки на HTML в оп посте).
Никто тебя дизайнить не будет заставлять, но я бы советовал почитать маленькую книгу «Дизайн для НЕдизайнеров. Робин Вильямс», она про оформление текста и как раз начального уровня.
>>491287
action="" вполне подойдет, почему нет? пустой URL ведет на ту же страницу.
Можно руками имя скрипта вписать например action.php
SCRIPT_NAME тоже можно
>>491288
Кыш
>>491295
Не очень понял, а зачем?
Алсо почитай-ка про шаблоны: http://www.phpinfo.su/articles/practice/shablony_v_php.html
Да, надо бы подробнее почитать про http. Добавил в список дел. Боюсь, он растет быстрее, чем я успеваю его выполнять.
Кстати, кроме http к сожалению есть еще куча всяких протоколов (пикрелейтед). Что о них нужно знать? Где почитать?
ну что бы финальным файлом был файл с версткой как бы. А весь код пилился в другом файле с расширением .пхп и отдавался в файл индекс.хтмл
Как это можно вынуть в документ .хтмл из .пхп?
>Дизайн для НЕдизайнеров
Нравится название, надо глянуть, спасибо. Я изначально и ориентировался на задания в оп-посте, могу сказать, что первые 11 не представляют трудности, хотя и со вкладками тоже, только лень вспоминать как анимацию делать. Да и последнее тоже несложно, только лениво в фотошоп лезть, ну и нет времени и желания находить времени на это. Через несколько месяцев займусь этим, ради разнообразия, а сейчас dive into php.
Достаточно почитать википедию чтобы знать в общих чертах, что за протокол и где используется.
Стоит почитать про:
TELNET
FTP (старый незашифрованный FTP с передачей пароля в открытую)
HTTP/HTTPS
SSH
IMAP (протокол доступа к почтовому ящику)
SMTP (протокол отправки почты)
SFTP (расширение SSH для передачи файлов)
Думаю, этого тебе хватит.
>>491339
Ты почитал статью? http://www.phpinfo.su/articles/practice/shablony_v_php.html
Просто делаешь файл в папке templates и подключаешь его через require из основного скрипта:
require _ _ DIR _ _ . '/templates/file.php';
>>491350
Анимация там на CSS без фотошопов.
Достаточно почитать википедию чтобы знать в общих чертах, что за протокол и где используется.
Стоит почитать про:
TELNET
FTP (старый незашифрованный FTP с передачей пароля в открытую)
HTTP/HTTPS
SSH
IMAP (протокол доступа к почтовому ящику)
SMTP (протокол отправки почты)
SFTP (расширение SSH для передачи файлов)
Думаю, этого тебе хватит.
>>491339
Ты почитал статью? http://www.phpinfo.su/articles/practice/shablony_v_php.html
Просто делаешь файл в папке templates и подключаешь его через require из основного скрипта:
require _ _ DIR _ _ . '/templates/file.php';
>>491350
Анимация там на CSS без фотошопов.
>Анимация там на CSS без фотошопов.
про фотошоп, я имел ввиду про вёрстку макета, вот это вот финальное задание лень делать.
Я бы порекоммендовал Седжвика. Все очень просто и интересно. Даже такому дубу как я, а я, между прочим, пять лет не мог понять рекурсии
У Седжвика через 2 недели стартует курс по алгоритмам.
https://www.coursera.org/course/algs4partI
ДС не знаю. Толковые джуны нужны. Но блядь 99 процентов даунов на собеседовании. Я серьезно.
Хотелось спросить архитектуре, вот сейчас написал модуль для книги, я ведь правильно думаю, что для заметок в книгах лучше всего подойдет другой модуль, а не в том же пилить это все?
Я тоже работаю, и тоже послу уроков оп-а устроился. Первую удаленку я нашел с недописанной задачей про студентов, но на тот момент я уже пол-года забил на php и написал django полнофункциональный форум, то есть знал ООП, mvc и framework. прошел еще курс на codecademy по jquery. Первое задание было допилить модуль для wp сделал, потом еще правки сайтов и дальше нашел уже норм работу. Уровень возрос разве чутку, крмое того умел работать c linux и знал паттерны, нормализацию.
У меня есть одна проблема, и звучит она как гринтекст ниже:
>session_start() [function.session-start]: Cannot send session cache limiter - headers already sent
Собственно, ошибка убирается перекодировкой страниц в UTF-8 без BOM, однако, в этой кодировке умирает кириллица. Пробовал в хедер прописывать метатегом charset=utf-8, но не помогает. Как быть?
Тебе надо перекодировывать не все файлы а только те которые в utf-8 с BOm. Те которые в 1251, трогать не надо.
То есть? Ведь в нужном файле у меня и есть кириллица. Я его перекодирую - получаются разные символы вместо кириллицы.
Ты по моему не понял. BOM — это невидимый символ который может опционально добавляться в файлы с кодировкой utf-8 (и вызывать ошибку). Соответственно если ты перкодируешь файл из utf-8 с BOM в utf-8 без BOM то кириллица сломаться не может.
В других кодировках BOM нету.
Отображение букв может сломаться если у тебя файл в кодирвке например 1251, а ты перекодируешь его в utf-8 (а браузер думает что страница в 1251).
сломаться русские буквы могли по 2 причинам:
— непраивльно перкодировал
— не поставил meta charset (в этом случае проблема решается ручным выбором кодировки в браузере)
Для начала определи в какой кодировке исходники.
Определить кодировку файла и наличие BOM гм... не знаю, как, наверно открыв файл в редакторе и посмотрев кодировку. Также можно это сделать просмотрев файл hex-редактором ( https://ru.wikipedia.org/wiki/Hex-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%BE%D1%80 ) вроде HxD .
Алсо никогда не редактируй код блокнотом винды.
Тег meta charset говорит барузеру в какой кодироке страница, он конечно нужен, так как иначе у тебя она может определяться неправильно, только в нем должна быть написана реально используемая кодировка.
> https://github.com/Si0n/register3/blob/master/index.php#L3
> require './template/main.php';
Ты подключаешь зачем-то шапку страницы в начале index.php, зачем? Ведь во-первых у тебя может быть страница на которой не нужна эта шапка, во-вторых, после ее подключения ты не можешь отправлять заголовки, ставить куки, делать редирект (который тебе понадобится при работе с формой). Я думаю этот инклюд надо убрать и переставить в шаблон.
Что-то не совсем понял, у меня main.php и так идем как шаблон и внутри него уже вызывается файл содержащий хедер, куда же дальше его там перекидать?
> Что-то не совсем понял, у меня main.php и так идем как шаблон
Это значит что если ты в list-action.php (или в регистрации) например захочешь выставить куку или сделать редирект ты это сделать не сможешь потому что после того как начался вывод тела страницы, нельзя делать редиректы и ставить куки.
Убери require './template/main.php'; из index.php и перенеси например в шаблоны.
Смотри как у тебя получается:
— подключить шаблон шапки
— выполнить какой-то код (в этом коде уже нельзя ставить куки и делать редиректы)
— подключить шаблон страницы
— выпонить код (в этом коде нельзя ставить куки и делать редиректы)
— подключить подвал
Как-то тут много подключений шаблонов и как-то вcе перемешано. Лучше бы сделать так:
— выполнить какой-то код (в этом коде работают и куки и редиректы)
— подключить нужный шаблон 1 раз
подключать шаблон лучше не из index.php, а из файлов-обработчиков вроде list-action.php, register.php и тд
Может я не очень понятно написал, но прооблем у твоего подхода две:
— не работают куки/редиректы после того как ты вывел шапку
— шаблоны разных частей страницы подключаются несколько раз и усложнаяют код, хотя можно обойтись без этого
У меня просто есть файл file.php, в нём есть содержимое: вперемешку код пхп и хтмл-куски с текстом на кириллице.
Без ВОМ пропадает кириллица, с ВОМ - появляется, но появляется и ошибка.
Когда я чарсет ставлю без ВОМ, то снова каракули заменяют буквы, т.е. комбо "файл без ВОМ"+"чарсет с ВОМ" мне не помогает почему-то.
А как заставить в одном файле работать и отображение кириллицы, и убрать ошибку - этого я и впрямь не понял.
https://github.com/Si0n/register3
Внес изменения некоторые, убрал громоздкий пагинатор сделал маленький, но не стал создавать для этого класс, мне показалось это лишним он и так вышел в пару строчек.
> Без ВОМ пропадает кириллица, с ВОМ - появляется, но появляется и ошибка.
надо убрать BOM и добавить в HTML код правильный тег meta charset
> Когда я чарсет ставлю без ВОМ, то снова каракули заменяют буквы,
Ты либо указываешь не ту кодировку в meta charset либо ты неправильно перекодировал файл и в реальности там не utf-8 а что-то другое.
Напомню, что ты можешь открыть свой файл hex-редактором и определеить какая там кодировка. Если utf-8 то русские буквы имеют вид вроде d0 92 d0 a5 d1 93 (d0/d1/d2/d3 идут через раз). Наличие BOM видно по первым 3 байтам файла, BOM выглядит как EF BB BF
А! meta charset не умеет эффекта если у тебя указана кодировка в заголовке Content-Type. То есть если у тебя в настройках php (php.ini или htaccess) стоит другая кодировка или в коде есть
header('content-type: text/html; charset=...')
То этот заголовок имеет приоритет перед тегом.
> https://github.com/Si0n/register3/blob/master/index.php#L2
> htmlspecialchars ( $_GET['page'], ENT_QUOTES)
Экранировать данные через htmlspecialchars надо там где они выводятся, то есть там где стоит
echo $page
или
<?= $page
Вот этот вот код немного сбивает с толку:
> case 'list' : include_once('./scripts/list_action.php'); break;
> if (isset($_GET['search'])) {
> include_once('./scripts/list_action.php');
Почему ты не можешь при поиске выставлять $_GET['page'] == list и соответственно убрать этот if? Выставить page можно через скрытый инпут в форме поиска. А то выглядт как костыль.
Алсо вместо include используй require так как он завершает скрипт при отстутвии нужного файла (а include нет).
>Экранировать данные через htmlspecialchars надо там где они выводятся, то есть там где стоит
я думал, наоборот надо там где они вводятся их экранировать чтобы извне вредоносный код не попал в скрипт.
> case '' : continue;
А что выводится если не передать скрипту page или передать неверное значение?
Я думаю надо выводить либо главную страницу либо страницу ошибки (главную наверно проще выводить будет).
Определись, что у тебя хранится в папке lib, а что в scripts? Почему файл https://github.com/Si0n/register3/blob/master/lib/Ini.php лежит в lib?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L15
> $link = "index.php?search=$search&p=";
Неверно подставляешь данные в URL. параметры в URL экранируются с помощью процентного кодирования и urlencode. А затем, если ты где-то выводишь ссылку, надо дополнительно экранировать спецсимволы в html через htmlpecialchars. то есть:
$link = '....?x= ' . urlencode($x) . '&y=1234';
... в шаблоне ...
ссылка: <?= htmlProtect($link) ?>
Более того, вместо urlencode удобно собирать ссылку через специально для этого сделанную функцию http_build_query.
Судя по тому, что ты используешь функциии в неправильном порядке, ты не очень хорошо понимаешь зачем они нужны. И я ведь писал в прошлый раз.
urlencode заменяет спецсимволы в ссылке на коды с процентами (читай вики https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Например в URL запрещен пробел но поисковая фраза может содержать пробел. urlencode заменяет пробел на %20 и ничего не ломается (а PHP автоматически расшифровывает этот код когда заполняет массив GET). Аналогично, поисковая фраза может содержать специсмволы вроде & ? # которые имеют специальное знаение в URL. Опять же urlencode заменяет их на правильные коды.
htmlspecialchars используется при выводе, чтобы специсмволы html < > & ' " были заменены на html-мнеомоники вроде & и кооректно востпринимались браузером.
Ты должен разобраться в этой теме. Чтобы помочь тебе, вот мини-задача:
Сделай страницу с формой из textarea и кнопки отправки. Никакого оформления и CSS не требуется, просто черный текст на белом фоне. При вводе любого текста и нажатия кнопки текст должен появиться внизу под textarea. Текст должен точно соответствовать введенному, корректно отображать все символы, включая пробелы и переводы строк (тут тебе поможет тег pre), точно так как их ввел пользователь. Проверь что сочетания вроде
%20%20
<b>test
&amp;
"'\<>
&t=1&
Отображаются ровно в том же виде как введены.
После того, как ты это сделаешь, добавь еще кое-что. Кроме текста, надо выводить ссылку вида script.php?text=....., которая содержит введенный текст и открыв которую мы можем увидеть его на странице.
Если тебе что-то непонятно в этой мини-задаче, задавай вопросы.
> case '' : continue;
А что выводится если не передать скрипту page или передать неверное значение?
Я думаю надо выводить либо главную страницу либо страницу ошибки (главную наверно проще выводить будет).
Определись, что у тебя хранится в папке lib, а что в scripts? Почему файл https://github.com/Si0n/register3/blob/master/lib/Ini.php лежит в lib?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L15
> $link = "index.php?search=$search&p=";
Неверно подставляешь данные в URL. параметры в URL экранируются с помощью процентного кодирования и urlencode. А затем, если ты где-то выводишь ссылку, надо дополнительно экранировать спецсимволы в html через htmlpecialchars. то есть:
$link = '....?x= ' . urlencode($x) . '&y=1234';
... в шаблоне ...
ссылка: <?= htmlProtect($link) ?>
Более того, вместо urlencode удобно собирать ссылку через специально для этого сделанную функцию http_build_query.
Судя по тому, что ты используешь функциии в неправильном порядке, ты не очень хорошо понимаешь зачем они нужны. И я ведь писал в прошлый раз.
urlencode заменяет спецсимволы в ссылке на коды с процентами (читай вики https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Например в URL запрещен пробел но поисковая фраза может содержать пробел. urlencode заменяет пробел на %20 и ничего не ломается (а PHP автоматически расшифровывает этот код когда заполняет массив GET). Аналогично, поисковая фраза может содержать специсмволы вроде & ? # которые имеют специальное знаение в URL. Опять же urlencode заменяет их на правильные коды.
htmlspecialchars используется при выводе, чтобы специсмволы html < > & ' " были заменены на html-мнеомоники вроде & и кооректно востпринимались браузером.
Ты должен разобраться в этой теме. Чтобы помочь тебе, вот мини-задача:
Сделай страницу с формой из textarea и кнопки отправки. Никакого оформления и CSS не требуется, просто черный текст на белом фоне. При вводе любого текста и нажатия кнопки текст должен появиться внизу под textarea. Текст должен точно соответствовать введенному, корректно отображать все символы, включая пробелы и переводы строк (тут тебе поможет тег pre), точно так как их ввел пользователь. Проверь что сочетания вроде
%20%20
<b>test
&amp;
"'\<>
&t=1&
Отображаются ровно в том же виде как введены.
После того, как ты это сделаешь, добавь еще кое-что. Кроме текста, надо выводить ссылку вида script.php?text=....., которая содержит введенный текст и открыв которую мы можем увидеть его на странице.
Если тебе что-то непонятно в этой мини-задаче, задавай вопросы.
В самом скрипте вредоносный код не опасен (это обычная строка, она в php не исполняется). Нужно только экранировать его перед вставкой в бд во избежание инъекции (используем подготовленные запросы с плейсхолдерами), а при выводе в браузер пропускать через htmlspecialchars, который заменяет теги на html-сущности.
Пусть меня поправят, если я не прав.
Тут https://github.com/Si0n/register3/blob/master/template/list.php#L33 переименуй переменную link в pagerLink чтобы понятно что это за ссылка и для чего.
Тут https://github.com/Si0n/register3/blob/master/template/list.php#L20 добавь экранироание выводимых данных. Конечно в имени или фамилии вряд ли будут спецсимволы, но лучше перестраховаться.
Вот тут вот неправильно: https://github.com/Si0n/register3/blob/master/lib/Student.php#L127
Работа с базой данных и SQL запросы должны быть только в маппере, модель сама не должна лезть в базу. Так как лезть в БД надо для проверки уникальности email, а модель это делать не может, функцию проверки правильности надо вынести наружу в отдельную функцию или класс (лучше класс, например StudentValidator).
В остальном, пока выглядит хорошо. После того как исправишь замечания, попробуй сделать регистрацию и редактироание профиля. Как ты наверно заметил, эти формы очень похожи и надо использовать для них один общий шаблон, а не два. Также, попробуй избавиться от сохранения ошибок в базу.
«Вредоносный» HTML код опасен только если он выведется на страницу без экранироания. В остальных местах он ничего сделать не может.
>>491657
Ты прав. Экранировать данные надо там где они используются/выводятся, а не на входе. Так как иначе невозможно понять все ли у тебя защищено. Например я вижу что в шаблоне не используется htmlspecialchars и как я проверю, экранированы там данные или нет. Каждую переменную что ли буду отслеживать, откуда она приходит? Мне некогда этим заниматься, я хочу видеть что все что выводится тут же экранируется.
Переделаю, я почему-то подумал что на вводе надо экранировать.
Обрабатывать данные на входе в скрипт можно когда ты точно знаешь что в них может быть. Например, номер страницы это число и можно пропустить его через intval() который гарантированно на выходе даст число и отбросит левые символы. Это можно сделать, дополнительная защита не помешает.
Или например сортировка: можно сортировать только по колонкам a, b, c. Можно поставить проверку которая будет проверять что в переменной могут быть только эти значения и заменять любое другое на значение по умолчанию. Это разумный подход.
Но например введенный пользователем комментарий может содержать абсолютно любые символы и мы хотим сохранить его в целости не коверкая никакими преобразоаниями (ну а при выводе разумеется используем htmlspecialchars).
А, кстати, вот тебе еще третий пункт для мини-задачи про экранирование: сохраняй все введенные тексты в базу и сделай страницу, где они выводятся списком (просто список без навигации и прочего) не теряя при этом никаких символов.
Я, видимо, аутист. Один из файлов стал выдавать такую ошибку независимо от ВОМ. Удалил символы посредством ВинХекса даже, а толку - ноль. Можешь мне детально объяснить, как сделать, чтобы было хорошо? Пишу код в Notepad++, манипуляции с тамошним Encode не помогают.
На скриншоте виден BOM в начале файла (EF BB BF) и видны русские буквы в utf-8 (по байтам типа D0 XX D1 XX)
Тебе надо:
1) открыть это тфайл текстовым редактором, убедиться что буквы видны
2) сохранить его как utf-8 без BOM
3) открыть hex редактором и убедиться что он выглядит примерно как раньше только первые 3 байта исчезли.
После этого твой файл будет в порядке и останется только вопрос как сказать о кодирвоке браузеру.
я кортинко)
http://manual.ucoz.net/_bd/4/20492991.png
>>491669
Зачем ты их этими hex-редакторами грузишь?
В обычном текстовом редакторе и так отображается кодировка (ну разве что в саблайме нужно прикрутить плагин, как обычно)
Тащемта это разные вещи.
Я давно не пользовался нотепадом++ и не помню как там сделана работа с кодировками, потому да универсальный способ диагностики таких проблем. Если есть способы проще то это конечно хорошо.
Насчет скриншота, меня путает наличие 2 похожих опций. Чем «кодировать» отличается от «преобразовать»?
В саблайме по моему проще, там есть File -> Reopen With Encoding -> ... и File -> Save With Encoding -> .. что имхо интуитивнее.
>>491676
Я догадываюсь, что разные, но не очень понимаю как они работают.
Для начала, спасибо, что нянчишься со мной.
И я сохраняю без ВОМ (т.е. делаю covert without BOM через np++), в итоге у меня появляются каракули.
Тегом стоит
><meta http-equiv="Content-Type" content="text/html; charset=utf-8">,
но как я понял, после session_start(); уже никто на этот тег внимания не обращает, да?
> но как я понял, после session_start(); уже никто на этот тег внимания не обращает, да?
сессии к кодировке не имеют отношения. Но ты не можешь делать сессион старт (и любые операции которые выводят заголоки) если вывел хотя бы 1 символ текста. Так как HTTP заголовки должны передаваться до тела страницы.Потому разумно не смешивать HTML и PHP а сначала сделать всю логику и обработать все данные, а только потом выводить HTML.
Насчет каракуль: метатег может не работать если у тебя есть заголовок с другой кодировкой.
Открой отладчик в браузере (Ctrl + SHift + I) на кладке network. перезагрузи страницу. Посмотри заголовки запроса и среди них Content-Type, есть ли там кодировка? Если есть то твой метатег игнорируется.
Затем открой исходный код страницы (Ctrl + U) и посмотри правильно ли выведен метатег, стоит ли раньше чем любой текст на русском?
"Кодировать" - меняет отображаемую кодировку. Преобразования текста не делает. То же самое, что в браузере, когда он показывает кракозябры, поменять кодировку отображения. На исходный документ это ес-но не повлияет.
"Преобразовать" означает именно конвертировать, пересохранить.
Но у этого товарища не из-за этого проблема, раз он выбрал
>covert without BOM
хз, там где-то в другом месте затык
Тогда логично назвать опцию не «кодировать» а «отображать как» так как «кодировать» это (по ощущениям) модифицирующая операция. Ну и идея саблайма с «reopen as » мне больше нравится в плане понятности.
У тебя до content-type идет текст, а также подключен непонятный яваскрипт. Попробуй как-то сделать чтобы ошибки не было (например закомментировать session_start или исправить ошибку)
Текст перед метатегом может привести к его игнорированию.
Судя по тексту ошибки (output started .... ) у тебя там то ли BOM в начале другого файла, то ли пустая строка или пробел.
Также, ты используешь оперу, попробуй посмотреть в каком-нибудь современном браузере для сравнения.
>подключен непонятный яваскрипт.
Это ему денверок поднасрал.
Не знаю, почему они его так любят? Омерзительная сборка.
Лично я очень доволен, что перешел на линукс.
Сервера ставятся из репозиториев апт-гетом в один клик одной строкой.
Расширения можно тоже потом легко подключать по мере необходимости.
Потому что XAMPP провёл мне по губам ошибкой с инклудами, с которой я не смог разобраться, в опенсервере столетний пхпмайадмин, который мне так и не удалось обновить без ошибок, в итоге я запустил попёрдывающий денвер и начал ковыряться с ним.
>>491700
Олсо, зашёл в денвере в httpd.conf, поменял там AddDefaultCharset windows-1251 на AddDefaultCharset utf-8, перезапустил денвер, а толку - ноль.
Но в заголовках теперь такое:
HTTP/1.1 200 OK
Date: Fri, 05 Jun 2015 11:49:03 GMT
Server: Apache/2.2.22 (Win32) mod_ssl/2.2.22 OpenSSL/1.0.1c PHP/5.3.13
X-Powered-By: PHP/5.3.13
Content-Length: 4824
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
И каракули.
Поделюсь бугуртом: капчую из деревни (город, но 10к населения всего) и тут проблема с напряжением электрическим. У меня ПК глох за сегодня уже раз этак 10. Свет тусклый, в микроволновке чего решишь разогреть - так она так надсадно гудит, что аж жаль её становится. Плита не греется почти тоже. Хуй знает, в чём проблема этого города, но я искренне радуюсь, когда по ночам дают нормальное напряжение, идёшь поссать, а в туалете - светло, а не полумрак уровня трёх лучин по углам помещения.
UPS/ноутбук надо использовать.
Проблема наверно с проводкой, я тоже с таким сталкиваешься, когда включашь слишком много и выбивает пробки.
>надо ставить не сборки а Apache/PHP/MySQL
Надо, да, но я ламер и вряд ли осилю их соединение без посторонней помощи. Там же наверняка много настроек сопутствует процессу?
>Может у тебя часть файлов в 1251?
Теперь нет, это я глобальные настройки поменял, выходит, так что всё должно быть в порядке.
>>491754
>UPS/ноутбук надо использовать
Понятное дело, что оно бы облегчило ситуацию. Но, чего нет - того нет. Да и я не у себя дома, а у родителей гощу, заодно пишу диплом, который сдавать в понедельник, а я только начал вот по большому счёту.
Ушёл теперь работать плотнее.
Есть сборник частых ответов:
https://gist.github.com/codedokode/7054af4a03865c4cc863
https://gist.github.com/codedokode/10774100
Гайд по командной строке
https://gist.github.com/codedokode/10539568
Может пригодится.
Повбрасываю сюда материалы, вдруг кому интересно.
Может еще оп спизданет что-нибудь умное, в смысле дополнит эту инфу замечаниями и своими ссылками.
Атрибут access для поля file позволяет указать разрешенные для загрузки миме-типы. Есть тонкие нюансы пятого хтмл и поддержки разными версиями браузеров.
http://htmlbook.ru/html/input/accept
Прогресс загрузки файлов (зеленый полосочкэ) можно выводить через сессии, регулировать частоту обновления. Не работает при включенной буферизации.
http://php.net/manual/ru/session.upload-progress.php
По умолчанию выглядит неплохо, но можно изменить его внешний вид, если поиграться с css
http://htmlbook.ru/practical/indikator-progressa
или js
http://postroyweb.ru/obshhie-uchebniki/uchebnik-html/indikator-progressa.html
Я кстати не знаю тонкости процессов буферизации, мне знакомо только принудительное включение через ob_start, но это не то.
Подозреваю, что сервер может включать буферизацию без спроса. Как бы это контроллировать?
Чтобы сменить временную папку для закачиваемых файлов, нужно прописать ее через директиву upload_tmp_dir в php.ini
Я если честно не понял, можно ли ее менять через ini_set. Кажется, нет. PHP_INI_SYSTEM вроде бы означает, что значение можно менять только в php.ini?
http://php.net/manual/ru/ini.list.php
Впрочем, хуй с ней. На рабочем сервере все будет хорошо с правами доступа для апача.
На локалке он по умолчанию попытается сохранить в какой-нибудь /tmp, я так думаю? Там же вроде доступ на запись для всех. Зачем я спрашиваю, сейчас проверю.
Ох, какие древние посты. Да, кстати, насчет единственности точки входа в функцию и единственности точки выхода из неё - это не моё. Это некий товарищ Э.Дейкстра, еще лет 40-50 назад сформулировал. Слышали про такого?
Структурное программирование, всё же, хоть чуть-чуть, но знать надо. Без него на работу не берут.
https://github.com/V3N0m21/StudentList
У меня есть вопрос про пагинацию. Как ее сделать правильно через запросы из базы, а не так через жопу как у меня сейчас? То есть как организовать взаимодействие классов Paginator и StudentMapper. Ну и мне хочется чтоб пагинация работала и с результатами поиска и с сортировкой, но я что-то совсем не понимаю как это сделать
>НЕДОПУСТИМО жёстко ограничивать длину строки; мягкое ограничение длины строки ДОЛЖНО быть 120 символов; строки СЛЕДУЕТ делать не длиннее 80 символов.
Где это выставить в настройках? Использую PhpStorm и Sublime.
А как надо было выполнить первое задание по JS?
Я не оп, но посмотрел твой код и вот что тебе скажу. Мне кажется хорошим тонном будет создать отдельный класс для списка студентов,а не хранить их в массиве, но да ладно. Надо хорошо продумать архитектуру. Хорошим тоном делать так что бы классы независили друг от друга, то есть класс пагинатор должен принимать на входе список и отображать его в виде страниц с пагинацей, тогда ты сможешь в него передавать любые результаты запросов, то есть ты запросил поиск, а потом передал результат пагинатору, а он уже делает свою работу.
Как-то так. Оп поправь если что не так
Алсо, с 'use strict' не работает нифига. Ну-ка поясняйте мне, уверен уже сто раз спрашивали. Добавил new, но и с этим проблемы тоже.
https://jsfiddle.net/0c9fhfa6/
>Мне кажется хорошим тонном будет создать отдельный класс для списка студентов,а не хранить их в массиве
Я тут вообще поссать вышел, но как-то это всё странно звучит. Класс (сущность) - "студент", их массив тоже может быть классом, но лишь при особой необходимости. Вроде какого-нибудь \ArrayCollection, только зачем?
Паджинацию мутить всегда непросто, если с нуля. Нужны базовые классы с поддержкой какого-нибудь DQL и лимитов. Почему бы не заюзать Doctrine? Она и в Symfony используется, и вообще - топовый ORM-фреймворк. И паджинацию уже (полу)нативно поддерживает.
Так у меня вроде сейчас так и есть, отдельный класс пагинатор, на вход которого подается массив объектов, и он даже нормально отображает первую страницу, но если ты хочешь открыть вторую или третью страницу, или отсортировать по другому полю, посылается гет запрос, и первоначальный массив объектов теряется. Ну и плюс пагинация у меня работает так, что запрос к базе возвращает всю таблицу, а не только информацию которую нужно отобразить.
Ты инструкции (точками с запятой) рандомно завершаешь, или в твоей шизофрении есть система?
Блин, это наследие питона. Не всегда вспоминаю.
Главное что ты должен помнить: загрузка файлов — это поверхность для атаки. Тебе могут попытаться закачать php файлы (под разными расширениями) или htacess (который позволяет менять настройки апача). Также файлы с странными именами не поддерживаемымим файловой системой.
> Атрибут access для поля file
Имей в виду так как это работает на стороне браузера, это не мера безопасности, а мера удобства (не показывать неподходящие файлы в диалоге выбора файла)
Реализация конечно ужасная:
> Прогресс закачки будет доступен в суперглобальной переменной $_SESSION в процессе закачки, а также при отправке POST-запросом переменной с именем равным значению опции session.upload_progress.name.
> Также возможно отменить загружаемый в данный момент файл, установив ключ $_SESSION[$key]["cancel_upload"] в значение TRUE.
Нормальные люди сделали бы 2 функции для этого (получить прогресс и отменить загрузку), а тут какие-то костыли и возня с сессиями.
> Я кстати не знаю тонкости процессов буферизации, мне знакомо только принудительное включение через ob_start,
Там речь о другом. ob_start это перехват выводимых через echo данных для сохранения или обработки.
Там имеется в виду модель с помощью которой веб-сервер обрабатывает загрузку файлов. Когда пользователь отправляет форму с файлом, то файлы передаются в теле POST запроса. Не надо быть гением чтобы понять что при закачке большого файла тело запроса тоже будет большим и его отправка займет большое время.
Апач не решает эту проблему (потому что это не очень-то и проблема), он просто при получении запроса вызывает PHP и PHP (еще до запуска твоего скрипта) принимает тело запроса и сохраняет в виде файла в временную папку. Это неплохой способ, но он требует в течение всей загрузки держать в памяти процесс Апача c модулем PHP. Некоторым это не нравится.
nginx реализует другой подход. Опционально можно включить там режим, когда тело запроса принимается nginx без обращения к php. nginx принимает файл, сохраняет его на диск, а только после этого запускает твой скрипт и передает ему данные о файле. Таким образом тратится меньше ресурсов, в первую очередь памяти.
Разумеется во втором варианте PHP не знает прогресс загрузки файла так как этим занимается не он. Ты должен запрашивать прогресс у нгинкса через какие-то его модули. Именно об этом говорит предупреждение.
Справедливости ради, разница в производительности там будет заметна только если у тебя куча народу одновременно загрудает огромные файлы. То есть для 99% сайтов это не нужно.
Ну и еще кое-что про прогресс. Современные браузеры позволяют отправлять файлы аяксом (в том число по частям что позволяет реализовать догрузку при обрыве) и получать информацию о прогрессе загрузки (не отправляя лишних запросов). Потому мне кажется можно сделать проще:
— в новых браузерах отправлять файл аяксом и рисовать полоску
— в старых грузить классическим способом и не выводить никаких полосок.
Таким образом сегодня эта фича (отслеживание прогресса через сервер) нужна только для старых браузеров. И я думаю, не стоит ради них заморачиваться, достаточно чтобы в них работала обычная загрузка.
Главное что ты должен помнить: загрузка файлов — это поверхность для атаки. Тебе могут попытаться закачать php файлы (под разными расширениями) или htacess (который позволяет менять настройки апача). Также файлы с странными именами не поддерживаемымим файловой системой.
> Атрибут access для поля file
Имей в виду так как это работает на стороне браузера, это не мера безопасности, а мера удобства (не показывать неподходящие файлы в диалоге выбора файла)
Реализация конечно ужасная:
> Прогресс закачки будет доступен в суперглобальной переменной $_SESSION в процессе закачки, а также при отправке POST-запросом переменной с именем равным значению опции session.upload_progress.name.
> Также возможно отменить загружаемый в данный момент файл, установив ключ $_SESSION[$key]["cancel_upload"] в значение TRUE.
Нормальные люди сделали бы 2 функции для этого (получить прогресс и отменить загрузку), а тут какие-то костыли и возня с сессиями.
> Я кстати не знаю тонкости процессов буферизации, мне знакомо только принудительное включение через ob_start,
Там речь о другом. ob_start это перехват выводимых через echo данных для сохранения или обработки.
Там имеется в виду модель с помощью которой веб-сервер обрабатывает загрузку файлов. Когда пользователь отправляет форму с файлом, то файлы передаются в теле POST запроса. Не надо быть гением чтобы понять что при закачке большого файла тело запроса тоже будет большим и его отправка займет большое время.
Апач не решает эту проблему (потому что это не очень-то и проблема), он просто при получении запроса вызывает PHP и PHP (еще до запуска твоего скрипта) принимает тело запроса и сохраняет в виде файла в временную папку. Это неплохой способ, но он требует в течение всей загрузки держать в памяти процесс Апача c модулем PHP. Некоторым это не нравится.
nginx реализует другой подход. Опционально можно включить там режим, когда тело запроса принимается nginx без обращения к php. nginx принимает файл, сохраняет его на диск, а только после этого запускает твой скрипт и передает ему данные о файле. Таким образом тратится меньше ресурсов, в первую очередь памяти.
Разумеется во втором варианте PHP не знает прогресс загрузки файла так как этим занимается не он. Ты должен запрашивать прогресс у нгинкса через какие-то его модули. Именно об этом говорит предупреждение.
Справедливости ради, разница в производительности там будет заметна только если у тебя куча народу одновременно загрудает огромные файлы. То есть для 99% сайтов это не нужно.
Ну и еще кое-что про прогресс. Современные браузеры позволяют отправлять файлы аяксом (в том число по частям что позволяет реализовать догрузку при обрыве) и получать информацию о прогрессе загрузки (не отправляя лишних запросов). Потому мне кажется можно сделать проще:
— в новых браузерах отправлять файл аяксом и рисовать полоску
— в старых грузить классическим способом и не выводить никаких полосок.
Таким образом сегодня эта фича (отслеживание прогресса через сервер) нужна только для старых браузеров. И я думаю, не стоит ради них заморачиваться, достаточно чтобы в них работала обычная загрузка.
> Кажется, нет. PHP_INI_SYSTEM вроде бы означает, что значение можно менять только в php.ini?
да
> На локалке он по умолчанию попытается сохранить в какой-нибудь /tmp, я так думаю?
Я бы вывел phpinfo() и проверил.
>>491794
> Это некий товарищ Э.Дейкстра, еще лет 40-50 назад сформулировал. Слышали про такого?
Хорошо бы ознакомиться с мтоивацией и выводами из этого утверждения, так как во-первых речь могла идти о сферических функциях в вакууме, во-вторых, там могли быть оговорки и дополнения. Ну и 50 лет назад программы и языки были другие, очень другие.
Тогда структурное программирование было модной новинкой так как позволяло отказаться от запутывающих логику ветвлений и циклов через goto. Это действительно отличная идея, которая позволила повысить качество и читаемость кода (хотя до сих пор найдутся желающие с этим спорить). Думаю что рассуждение про единственную точку выхода тоже имеет под собой какие-то причины (например необходимость освобождать ресурсы) которые не всегда могут быть применимы.
Мы должны рассматривать утверждения именно в контексте того времени. Дейкстра имел в виду не «всегда используйте структурное программирование», а «вместо простыни с goto лучше используйте структурное программирование».
Надеюсь что ты (как и я) стараешься не слепо следовать принципам, а понимать проблемы которые они решают.
Множественный return в моем слуае решает проблему усложенния кода увеличением вложенности.
Потому если ты хочешь поспорить то тебе надо не просто процитировать Дейкстру, а сделать логическую цепочку, какая проблема в моем коде, чем это плохо и как ситуацию можно исправить и улучшить. Я тебе привел пример про процедуру с 4 предварительными условиями.
>>491798
> Как ее сделать правильно через запросы из базы,
Просто добавь в метод выборки и поиска студентов параметры offset и limit. И скорее всего нужен еще параметр задающий сортировку. Если ты хочешь сделать посложнее, то сделай чтобы по умолчанию у них например стояло null и если они не укзаны то выбираются все студенты (хотя это не требуется).
То есть смотри, лучший вариант — это передавать все нужные паарметры функции. Если у тебя выборка зависит от:
— слова для поиска
— поля сортировки
— offset/limit
То их и надо передавать, а функция пусть делает нужный SQL запрос.
Также понадобится функция считающая общее число студенов либо число студентов соответствующих запросу (для вычисления числа страниц).
Вот тут написано как в PhpStorm вывести черту справа чтобы видеть не перешел ли ты ограничение.
Я не знаю, но возможно эта настройка также как-то влияет на автоматическое форматирование кода.
В саблайме есть опция меню view - ruler и наверно настройки в конфиге: http://stackoverflow.com/questions/25900954/80-characters-right-margin-line-in-sublime-text-3
Я не использую черту, я на глаз вижу когда строка становится слишком уж длинный. Сейчас проверил свой код - большинство строк укладывается в 80, и только несколько вылезают на 110-120 символов. У ОПа глаз-алмаз. Я думаю ты со временем без полоски справа нанешь чувстовать эту ширину.
Само ограничение там по 2 причинам:
— древние терминалы имели ширину 80 символов и длинные строки было неудобно читать (надо использовать прокрутку). Сейчас неудобно читать людям у которых узкий экран, много панелей сбоку или крупные буквы
— есть определенаая ширина текста шире которой человеку приходится больше двигать зрачки туда-сюда, это как раз 60-80 символов (для обычного текста, зависит от шрифта, размера и межстрочного расстояния, чем теснее строки тем труднее за них держаться взглядом), код по моим ощущением читается легче и его можно делать чуть шире. Например на этом форуме ширина не ограничена, но он рассчитан на короткие посты в 2-3 строки на которых не устанешь. Но большой текст шириной на весь экран читать тяжело.
ссылку забыл для phpstorm: http://stackoverflow.com/questions/21873543/how-to-set-line-limit-length-for-different-types-of-files
>>491818
Роботом http://dkab.github.io/jasmine-tests/?spec=1 проверял? Я вижу что он выдает ошибки. Проверь. Помни что робот несовершеннен и в случае сомнений пиши в тред.
По твоему коду,
> this.init = init - step;
this здесь глобальный объект и this.init создает глобальную переменную init что зло. В JS функция это просто функция и она не создает никаких объектов при вызове и this в ней не стоит использовать. this используется в функциях-конструкторах, методах классов (точнее их имитации).
Тебе нужна обычная переменная.
> var sequence = function(init, step) {
По моему лучше читается function sequence ... хотя это больше дело вкуса.
Ну понятно, опять проповеди начались. "Отступы и фигурные скобки юзать обязательно, а то, с чем я не согласен - нахуй". Структурное программирование на примере одного ОПа.
Да, я как-то забыл, что сейчас все на аяксе.
Но было интересно узнать, как это можно сварганить средствами php.
По поводу безопасности, вроде бы решением будет:
а) отслеживать mime-типы загружаемых файлов, но это спасет только от хакера Васи из 10-А
б) положить файл .htaccess, в котором будет запрещено исполнение скриптов в текущей (или вложенных директориях), чтобы сервер их отдавал как плэйн текст.
Не знаю только, как обезопаситься от загрузки собственно файла .htaccess поверх моего родного.
В моем случае я меняю имя загружаемым файлам, пропуская их через sha1( $oldName + time() ), чтобы пользователь Катюшка Катюшка, попытавшись загрузить avatar.jpeg, не затерла аватарку с таким же именем другого пользователя.
Так что хакерский .htaccess все равно будет сохранен под именем 9a97508deae2900364701c175d45e9887cfb093a и не будет иметь никакой силы.
Это решение годится, или есть другие варианты?
> хорошим тонном будет создать отдельный класс для списка студентов
У него есть класс Student, ты предлагаешь еще сделать класс StudentCollection? Какие у него будут методы? Какая выгода в сравнении с массивом?
Кстати в PHP уже есть объект-коллекция: http://php.net/manual/ru/class.arrayobject.php
Мое мнение, для простой задачи класс-коллекция излишен, массива вполне хватит. Если у тебя есть аргументы, напиши. Помни что это обучающий тред и хорошо бы знать почему A лучше чем B.
> Хорошим тоном делать так что бы классы независили друг от друга, то есть класс пагинатор должен принимать на входе список и отображать его в виде страниц с пагинацей
Я не согласен с такой архитектурой. Я считаю пагинатор должен отвечать только за отображение гм... пагинации. Соответственно ему не нужен список сущностей, ему достаточно знать их число и номер страницы (и шаблон ссылки чтобы их генерировать).
Вот как я вижу самую простую реализацию:
$pager = new Pager($currentPage, $totalPages, $linkTemplate);
// в шаблоне
<?php foreach ($pager->getPageLinks() as $link => $title): ?>
<a href="<?=html($link)"><?= html($title) ?></a>
<?php ?>
Преимуществом я вижу то что мой пагинатор занимается только рассчетом номеров страниц которые надо вывести и ничем более. При этом он способен выводить их по-умному, например показывая только часть номеров. Если у тебя другая идея, опиши ее подробнее с кратким (кратким!) примером использования.
> и отображать его в виде страниц с пагинацей,
По моему это переусложеннеи. У тебя пагинатор не только номера страниц выводит, но и таблицу с поиском-сортировкой? Мне кажется таблицу мы выведем и без него, это не его задача.
> хорошим тонном будет создать отдельный класс для списка студентов
У него есть класс Student, ты предлагаешь еще сделать класс StudentCollection? Какие у него будут методы? Какая выгода в сравнении с массивом?
Кстати в PHP уже есть объект-коллекция: http://php.net/manual/ru/class.arrayobject.php
Мое мнение, для простой задачи класс-коллекция излишен, массива вполне хватит. Если у тебя есть аргументы, напиши. Помни что это обучающий тред и хорошо бы знать почему A лучше чем B.
> Хорошим тоном делать так что бы классы независили друг от друга, то есть класс пагинатор должен принимать на входе список и отображать его в виде страниц с пагинацей
Я не согласен с такой архитектурой. Я считаю пагинатор должен отвечать только за отображение гм... пагинации. Соответственно ему не нужен список сущностей, ему достаточно знать их число и номер страницы (и шаблон ссылки чтобы их генерировать).
Вот как я вижу самую простую реализацию:
$pager = new Pager($currentPage, $totalPages, $linkTemplate);
// в шаблоне
<?php foreach ($pager->getPageLinks() as $link => $title): ?>
<a href="<?=html($link)"><?= html($title) ?></a>
<?php ?>
Преимуществом я вижу то что мой пагинатор занимается только рассчетом номеров страниц которые надо вывести и ничем более. При этом он способен выводить их по-умному, например показывая только часть номеров. Если у тебя другая идея, опиши ее подробнее с кратким (кратким!) примером использования.
> и отображать его в виде страниц с пагинацей,
По моему это переусложеннеи. У тебя пагинатор не только номера страниц выводит, но и таблицу с поиском-сортировкой? Мне кажется таблицу мы выведем и без него, это не его задача.
Ну меня тоже раздражает этот культ личности в треде, и как местные омеганы лижут ему жопу.
Но как халявный репетитор для меня очень важен. Нельзя рубить курицу с золотыми яйцами, или как там в пословице.
Так что не доебывай нашу священную корову, а то обоссу.
Просто придерживаюсь принципа одна сущность, один класс легкие приложения оно сильно не пергрузит, а в больших это мастхев, я вообще кодил до этого вовсе не на php, спасибо про ссылочку на коллекцию.
Про пагинацию немного не так, но да ладно, я все равно еще нуб полный.
Я бы делал в пагинаторе отдельный класс, который бы использывался в контроллере, когда нужно, конструктором был бы метод сориторвки, если он пуст, простая пагинация, такие дела
use strict лучше ставить внутри функции, так как иначе он может даже не срабоать (это зависит от того как именно jsfiddle выполняет твой код).
Точку с запятой JS умеет вставлять но он легко может разломать твой код потому я советую всегда ставить ее явно.
>>491832
Не используй this и new, используй обычные переменные. Алсо учебник learn.javascript.ru если ты не видел его, вот нужная глава: https://learn.javascript.ru/closures
>>491837
В PHP уже есть ArrayObject, но считаю дял простой задачи нет смысла делать класс коллекцию так как мы не будет в нее добавлять никакие методы. В больших приложениях свой класс-коллекция может быть удобен.
>>491837
> Нужны базовые классы с поддержкой какого-нибудь DQL и лимитов
Посмотри мой пост выше, я считаю пагинация не должна заниматься выборкой данных, а только выводом номеров страниц и все. Я видел конечно решения которые как-то насаживаются например на Query Bulder и добавляют к нему LIMIT (и по моему эти решения очень неуниверсальны) но у нас тут нет ни доктрины ни query builder. Это простая задача для наичинающих.
>положить файл .htaccess
Не забывай, что его поддерживают далеко не все серверы.
>попытавшись загрузить avatar.jpeg, не затерла аватарку с таким же именем другого пользователя
В папке .../files создается иерархия подкатологов по пользователям. Или не создается. Ну и в PHP есть такая функция - basename(). Отделяешь основное имя, и в цикле, инкрементируя, проверяешь наличие файла, ищешь avatar_N.jpg. Это, к примеру, позволяет одному юзеру иметь файлы с одинаковыми именами.
> Почему бы не заюзать Doctrine?
ПОтому что задача на список студентов это первое серверное приложение (после курса по основам PHP). Какая доктрина? Я сам например не все в ней знаю (что касается лениых/жадных загрузок. Например: можно ли сделать жадную загрузку не через fetch-join, а через несколько простых запросов? Можно ли к масиву сущностей догрузить связанные одним запросом? как реализована сортировка связанных сущностией которая пишется в аннотации @OrderBy? Если я загрузил все связанные в дерево Gedmo сущности как сделать чтобы getChildren не вызывал запроса?), а начинающий от нее умрет.
>>491839
> Ну и плюс пагинация у меня работает так, что запрос к базе возвращает всю таблицу, а не только информацию которую нужно отобразить.
Надо добавить LIMIT будет.
>>491916
Я на PSR основываюсь, отсюда скобки
>>491917
> Ну и плюс пагинация у меня работает так, что запрос к базе возвращает всю таблицу, а не только информацию которую нужно отобразить.
Тут есть подвох, некоторые хостеры запрещают опцию php_value engine off в htaccess. Один анон с файлообменником так погорел выложив проект на хостинг (к счастью я обнаружил баг первым). Потмоу если код не заточен под определенное окружение, этого недостаточно. Я бы переименовывал файлы или ставил расширение типа .txt
> Не знаю только, как обезопаситься от загрузки собственно файла .htaccess поверх моего родного
Это можно запретить в конфиге Апача, но 1) легко ошибиться или забыть и оставить дыру 2) на хостинге у тебя может не быть прав редактировать конфиг
Выход тут только переименование.
> пропуская их через sha1( $oldName + time() )
Откуда такая любовь к хешам? Ну представь у тебя папка с 1000 таких файлов и как ты в ней ориентироваться будешь? Я бы использовал id файла, дату загрузки, транслит исходного названия или что-то еще человекочитаемое. Я лично ненавижу имена-хеши так как иногда приходится в них копаться.
> не затерла аватарку с таким же именем другого пользователя.
Для этого достаточно приписывать id или что-то уникальное.
> Почему бы не заюзать Doctrine?
ПОтому что задача на список студентов это первое серверное приложение (после курса по основам PHP). Какая доктрина? Я сам например не все в ней знаю (что касается лениых/жадных загрузок. Например: можно ли сделать жадную загрузку не через fetch-join, а через несколько простых запросов? Можно ли к масиву сущностей догрузить связанные одним запросом? как реализована сортировка связанных сущностией которая пишется в аннотации @OrderBy? Если я загрузил все связанные в дерево Gedmo сущности как сделать чтобы getChildren не вызывал запроса?), а начинающий от нее умрет.
>>491839
> Ну и плюс пагинация у меня работает так, что запрос к базе возвращает всю таблицу, а не только информацию которую нужно отобразить.
Надо добавить LIMIT будет.
>>491916
Я на PSR основываюсь, отсюда скобки
>>491917
> Ну и плюс пагинация у меня работает так, что запрос к базе возвращает всю таблицу, а не только информацию которую нужно отобразить.
Тут есть подвох, некоторые хостеры запрещают опцию php_value engine off в htaccess. Один анон с файлообменником так погорел выложив проект на хостинг (к счастью я обнаружил баг первым). Потмоу если код не заточен под определенное окружение, этого недостаточно. Я бы переименовывал файлы или ставил расширение типа .txt
> Не знаю только, как обезопаситься от загрузки собственно файла .htaccess поверх моего родного
Это можно запретить в конфиге Апача, но 1) легко ошибиться или забыть и оставить дыру 2) на хостинге у тебя может не быть прав редактировать конфиг
Выход тут только переименование.
> пропуская их через sha1( $oldName + time() )
Откуда такая любовь к хешам? Ну представь у тебя папка с 1000 таких файлов и как ты в ней ориентироваться будешь? Я бы использовал id файла, дату загрузки, транслит исходного названия или что-то еще человекочитаемое. Я лично ненавижу имена-хеши так как иногда приходится в них копаться.
> не затерла аватарку с таким же именем другого пользователя.
Для этого достаточно приписывать id или что-то уникальное.
Для таблиц width и height примерно равносильны min-width и min-height то есть задают минимальную ширину. Это сделано с благими подуждениями, чтобы таблица растягивалась при большом содержимом.
Тебе надо разобраться почему таблица растягивается, может надо ограничить размер контента в ней, может надо использовать table-layout: fixed.
Вот старая статья по теме http://htmlbook.ru/samlayout/verstka-s-pomoshchyu-tablits/osobennosti-tablits
http://web-standards.ru/articles/css-techniques-p1-tables/
Также в таблицах может не работать position: relative/absolute если он опирается на элементы таблиц.
Конечно верстальщик должен это знать и понимать.
По-моему, это полное уебанство - задавать таблице фиксированную ширину в пикселях. Хоть в процентах задай, если срака чешется.
Не, я же пытаюсь начать делать файлообменник, там же все загрузки анонимные(?)
Я конечно при проектировании бд учел возможность в будущем добавить регистрацию, но пока будем считать, что в таблице юзеров только anonymous и admin .
Делать каталог каждому юзеру не выход.
>>491938
>Откуда такая любовь к хешам? Ну представь у тебя папка с 1000 таких файлов и как ты в ней ориентироваться будешь?
По базе, конечно. Там столбец original_name для вывода названия пользователю и server_name для правильных ссылок.
Конкатенировать название с датой тоже вариант.
Хотя я не понимаю, откуда такая нелюбовь к хешам.
Понятия не имею, зачем руками лазить по папке загрузок. Там явно будет больше 1000 файлов, под миллион, если не чистить. Так что называй хоть 00000001.jpeg, хоть kjhajhdakdfhkhashkafkhafkjh, по-барабану ничего без фильтров не найдешь.
Ладно, покидаю вас господа. Соседское быдлецо включило музончик, не могу сосрредоточиться.
Всем паулоктуса
https://www.youtube.com/watch?v=R3tH2crga_8
При чем тут ОП? Я тебя попросил объяснить 2 вещи:
— почему несколько точек выхода это плохо (цитата Дейкстры не объясняет)
— как решить ситуацию с 4 выходами из функции не теряя читаемость
А ты не аргументируешь и переходишь на личность ОПа, вот он такой плохой. Раз ОП плохой, объясни лучше чем он.
У нас в треде не все хотят помогать новичкам. Периодиечски заходят люди которые просто хотят померяться авторитетом, посамоутверждаться. Вместо помощи и объяснения они просто бросают новичкам категоричные утверждения. Это можно делать в любом другом треде /pr (этим там и занимаются в основном), но не тут. Конечно и мне не надо поддаваться на провокации, признаю.
Я специально написал пост: >>487140 Если кто-то хочет помочь начинающим, замечательно, я думаю все будут только рады. Но как там написано, мы ориентируемся на мейнстрим, на распространенные стандарты и библиотеки и любители всяких альтернативных подходов (табы рулят, ООП не нужен) тут не приветствуются. Идите в другие треды, там все ваши друзья собрались.
Выбор единиц зависит от ситуации. Может быть у него какие-то элементы должны с таблицей по ширине совпадать. Потому сказать «пиксели не нужны» я не могу, хотя конечно их лучше избегать и полагаться на автоматическое определние ширины.
>>491947
> По базе, конечно.
Разве не удобнее когда без базы все очевидно? Смотри, дело твое, но я не понимаю чем тогда sha луше чем например id из базы. Id короче и проще читается.
>Вместо помощи и объяснения они просто бросают новичкам категоричные утверждения
У тебя 51-ый (!) тред (кончается). В последних постах прошлого треда ты мне сказал, что твои ученики еще не знают про цикл while(). И ты, вместо учебы, катаешь простыни про "Дейкстра отстой, скобки рулят!!11"?
Да, я об этом просто не подумал. У меня и так ограниченные мыслительные способности, а тут еще внешние раздражители (уровень шума на улице).
Вариант с ориг.именем + id для названий файлов пожалуй идеален.
А у вас как со стрессоустойчивостью, мальчишки и девч0нки?
Я как-то в студенческие годы работал в быдло-офисе полгода, чуть не ебанулся. У них там круглосуточно орало радио (попса + шансон), я не мог сосредоточиться, ничего не получалось, даже когда у меня что-то спрашивали, я не мог разобрать слов, как будто меня контузило снарядом.
Не вижу аргументации по теме. Кстати я тут нагуглил на первой же строчке гугла, в википедии тема early exit давно уже разобрана по полчкам. ты даже скопировать аргументы оттуда поленился: http://en.wikipedia.org/wiki/Structured_programming#Common_deviations
> что твои ученики еще не знают про цикл while(). И ты, вместо учебы, катаешь простыни про
Я старался уменьшить в учебнике объем информации, оставив в самом начале только самые важные конструкции. While там объясняется но не в начале, а ближе к концу. Почитал бы хоть.
> "Дейкстра отстой, скобки рулят!!11"?
Я не говорил ничего подобного, и не понимаю как наличие скобок мешает реализации структурного программирования. Это ты уперся с одной цитатой которую ты не можешь объяснить и аргументировать хотя бы копипастой из википедии.
>>491962
> У них там круглосуточно орало радио
Я работал в тихом опенспейсе без радио и дома, потому не знаю. Но вообще мне кажется здоровый пофигизм полезен.
> я не мог сосредоточиться,
ну сказал бы что слишком громко и сделаешь поитише. Вообще в нормальных IT компаниях такого нет, работать действительно неудобно в такой ситуации.
>я не мог сосредоточиться, ничего не получалось...
Книга Тома Демарко и Тимоти Листера «Человеческий фактор: успешные проекты и команды» – перевод 2-го издания всемирно известного бестселлера об управлении проектами разработки ПО. Первое издание содержало революционные по тем временам (1987 г.) идеи, которые выдержали проверку временем. Авторы скорректировали свои выводы и добавили несколько новых глав. Ценность этой книги в том, что в ней описываются принципы, за каждым из которых стоит реальная история. Все главы содержат наблюдения и новаторские подходы, которые заставят читателей и руководителей увидеть важные вопросы в новом, более разумном ракурсе. С юмором и мудростью, обретёнными за годы руководства и консультирования, Демарко и Листер демонстрируют, что сложнейшие проблемы разработки ПО имеют человеческую, а не техническую природу.
Я тут это, решил стать пхпмакакой и зарабатывать себе на фисташки с пивом и игры дороже, чем сдача с макдональдса. Вообще собирался стать яблоблядью, но ниасилил разработку под него почти вообще ни в каком виде. Я знаю HTML, CSS, JS, jQuery и PHP скорее больше в теории, но использовал и на практике (пытался делать сайт на WP под заказ, но заказчик дропнул проект; писал юзерскрипты для Greasemonkey; Да, сука, даже на тогда модном юкозе пилил сайтец и там всё это очень нужно было). Так вот,
1) Какие у меня перспективы?
2) Как мне начать работать? Где можно повторить забытое (какую книгу посоветуете, форэкзампл)? В каком месте искать работу? Да и вообще, накидайте факов и гайдов для таких, как я.
Алсо добью тебя Мартином Фаулером: http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html
В оп-посте есть все материалы и задания для самопроверки разных уровней сложности.
Берешь материал, пытаешься понять, пробуешь реализовать.
Если непонятно, задавай конкретные вопросы.
Все книги начального уровня отстой, читай мануалы в интернете.
Работу искать на хедхантере или других крупных сайтах с вакансиями.
Ох, добил, я умираю.
Теперь вот пришло странное письмо от робота. Не понимаю, это мои письма не доставлены, или мне что-то не дошло? Ну-ка, умельцы.
Что тут написано?
https://gist.github.com/anonymous/577bf266c2258b21de29
Почему регулярочка не пропускает эти строки?
$name = 'Ё-чжин_Ха'; //Ёко_Хонна Петтер_Ёргенсон Ме-ён_Ё Ким_Сон_Ён
if (preg_match("#^[ёа-я.’-]+?_[ёа-я_.’-]+$#i", $name, $match)) {
echo 'good';
} else {
echo 'bad';
}
вроде как не нужен
сайт cp1251
C url приходит имя в утф, но там опять такие rawurldecode и iconv в cp1251
Тогда надо праивльно выставлять локаль (и убедиться что она установлена на сервере) и если это не сработает, то страдать. Сейчас utf-8 стандарт дефакто и ради 1251 никто pcre перепиливать не станет. Возможно что с 1251 например флаг i не работает.
Да, анон, да
preg_match() [function.preg-match]: Compilation failed: invalid UTF-8 string at offset 2
Итак, почему же не проходит ебучая ё
А локаль?
Ты можешь проверить работает ли буква на простой регулярке вроде:
/ё/
/ё/i
/Ё/
/[Ёё]/
Так, анон, ты оказался ближе всех.
Добавил А-Я, прошла регулярка. Только какого хуя тогда такие имена проходили пример "Вин_Дизель"
Ты по моему не очень понял как работают одноюайтные кодировки и что такое локаль.
В однобайтных кодировках 1 символ кодируется 1 байтом. Как известно байт может принимать знаечния от 0 до 255. Символы с кодами 0-31 невидимые, символы 32-127 общие и соответствуют ASCII: https://ru.wikipedia.org/wiki/ASCII , а вот символы 128-255 разные в разных кодировках. В cp1251 там русские буквы ( https://ru.wikipedia.org/wiki/Windows-1251 ), в европейских кодировках там всякие буквы с точками и кружочками.
Очевидно не зная кодировки ты не можешь сказать какая буква закодироана кодом например 156. Соответственно ты не можешь сказать заглавная она или прописная и какая у нее пара. Чтобы ответить на этот вопрос, надо знать кодировку, а она в PCRE определяется локалью.
Локаль определяет используемый язык и кодировку (и не только, например в линуксе она определяет на каком языке выводят сообщения программы, как форматируют числа и даты и т д). Она задается через переменные окружения вроде LANG, LC_ALL и тд. Локаль под Линукс имеет вид вроде ru_RU.utf8 (русский язык, Россия, utf8). В Windows идентификаторы другие. PCRE смотрит на локаль и пытается найти файл с информацией о кодах символов. То есть мало задать локаль, надо чтобы на копьютере был файл с информацией о ней («чтобы локаль была установлена»). Если локаль неправильная или файла нет, то PCRE молча проигнорирует ошибку и будет работать в режиме ASCII, а все символы с кодами 128-255 будет считать непонятными значками, у которых нет ни заглавных ни прописаных букв.
Соответственно чтобы опция i корректно сопоставляла буквы, надо выполнение таких условий:
— локаль правильно задана
— локаль установлена в системе
В твоем случае одно из них нарушается. Если локали нет, то не страшно, просто флаг i не работает. Но если задана неправильная локаль, то все хуже: заглавные/прописные буквы сопоставляются по другим правилам (как будто у тебя другая кодировка) и регулярка будет работать неправильно.
Видимо у тебя неправильно задана локаь и например pcre считает что буква В это заглавная версия буквы ж и потому дает ложные срабатывания.
Я же предупреждал что ты будешь страдать?
Ты по моему не очень понял как работают одноюайтные кодировки и что такое локаль.
В однобайтных кодировках 1 символ кодируется 1 байтом. Как известно байт может принимать знаечния от 0 до 255. Символы с кодами 0-31 невидимые, символы 32-127 общие и соответствуют ASCII: https://ru.wikipedia.org/wiki/ASCII , а вот символы 128-255 разные в разных кодировках. В cp1251 там русские буквы ( https://ru.wikipedia.org/wiki/Windows-1251 ), в европейских кодировках там всякие буквы с точками и кружочками.
Очевидно не зная кодировки ты не можешь сказать какая буква закодироана кодом например 156. Соответственно ты не можешь сказать заглавная она или прописная и какая у нее пара. Чтобы ответить на этот вопрос, надо знать кодировку, а она в PCRE определяется локалью.
Локаль определяет используемый язык и кодировку (и не только, например в линуксе она определяет на каком языке выводят сообщения программы, как форматируют числа и даты и т д). Она задается через переменные окружения вроде LANG, LC_ALL и тд. Локаль под Линукс имеет вид вроде ru_RU.utf8 (русский язык, Россия, utf8). В Windows идентификаторы другие. PCRE смотрит на локаль и пытается найти файл с информацией о кодах символов. То есть мало задать локаль, надо чтобы на копьютере был файл с информацией о ней («чтобы локаль была установлена»). Если локаль неправильная или файла нет, то PCRE молча проигнорирует ошибку и будет работать в режиме ASCII, а все символы с кодами 128-255 будет считать непонятными значками, у которых нет ни заглавных ни прописаных букв.
Соответственно чтобы опция i корректно сопоставляла буквы, надо выполнение таких условий:
— локаль правильно задана
— локаль установлена в системе
В твоем случае одно из них нарушается. Если локали нет, то не страшно, просто флаг i не работает. Но если задана неправильная локаль, то все хуже: заглавные/прописные буквы сопоставляются по другим правилам (как будто у тебя другая кодировка) и регулярка будет работать неправильно.
Видимо у тебя неправильно задана локаь и например pcre считает что буква В это заглавная версия буквы ж и потому дает ложные срабатывания.
Я же предупреждал что ты будешь страдать?
Предупреждал лол
Схоронил твой пост в нотепад. Спасибо за труд.
А как посмотреть установленую локаль для скрипта, сли это cms? Я хз есть там где то setlocale или нет.
Если нет setlocale? Судя по мануалу http://php.net/manual/ru/function.setlocale.php это встроенная функция. Там написано что
setlocale(LC_ALL, '')
постаавит текущую локаль из переменных окружения и вернет ее (или false при ошибке).
Алсо переменные окружения (LANG, LC_*) можно учидеть в phpinfo()
Спасибо тебе, анон. Добра!
Вот у нас будет разрешено загружать допустим три типа данных: фильмы, музыку и картинки.
Соответственно у нас будет отличаться представление (html-шаблон) для этих разных типов контента.
Значит, мне нужно как-то опознавать, к какому типу относится текущий файл.
Как лучше сделать:
сохранять тип файла из (супер?)глобального массива $_FILES вместе с именем файла прямиком в базу,
или определять тип файла непосредственно перед выводом?
Первый способ нехорош тем, что $_FILES штука ненадежная в этом плане, туда можно подсунуть неправильные данные и у меня как минимум перекосится верстка, а то и выдаст ошибку, когда видеоплеер попытается прочитать картинку, например.
Как проверить валидность того, что нам сообщает $_FILES['inputName']['type'] я не знаю.
Второй способ плох тем, что я не знаю, какими функциями можно определить миме-тип файла.
Только что нагуглил модуль fileinfo, сейчас буду читать.
http://php.net/manual/ru/intro.fileinfo.php
Советы? Я на верном пути, или есть другие варианты?
> сохранять тип файла из (супер?)глобального массива $_FILES
это тип который прислал браузер и там может быть неточная или неверная информация. Тип надо определять библиотекой вроде Id3 по содержимому файла.
Алсо прежде чем делать видеоплеер изучи какие форматы поддерживаются:
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
http://caniuse.com/#feat=webm
http://caniuse.com/#feat=mpeg4
http://caniuse.com/#feat=ogv
https://helpx.adobe.com/flash/kb/supported-codecs-flash-player.html
Нет единого формата который бы гарантированно воспроизводился везде. Ютуб конвертирует все видео в пару форматов типа H.264, webm и формат для флеша (Vp6 может?) для старых браузеров (так как в них нет HTML5 тега video).
Для файлообменника делать конвертер наверно излишне, но если тебе очень-очень хочется, то это возможно (хотя и непросто и потребует много чего изучать).
> Только что нагуглил модуль fileinfo, сейчас буду читать.
Это тоже вариант, эта функция анализирует содержимое файла по базе шаблонов. Но библиотека id3 умеет еще и информацию о битрейте, разрешении, исполнителях вынимать.
Вот эта штука работает
$finfo = new finfo(FILEINFO_MIME_TYPE);
echo $info->file('path/to/file');
>>492154
Да погоди ты с видео, я пока только намечаю, прокладываю стезю, так сказать. Учусь проектированию, мол в будущем планируется прикрутить и поддержку видео, и просмотр pdf-файлов, и игровые автоматы с блудницами. Может это никто и не будет делать, а может будет кто-то другой, но предусмотреть добавление всех этих возможностей надо.
Я видел твои посты о видеоформатах выше >>490400, даже сохранил куда-то. Не помню только куда. У меня уже свалка в закладках. Надо либо делать бложик, либо сохранять все это в базу, а то я потом не разгребу. Особенно если браузер или система сдохнет без возможности восстановить закладки.
вторая задачка с кредитами, где я неправ? Как-то ночью туго соображаю почему зацикливается
извините, слеповат, разобрался.
В общем вот задачка на два кредита, но какие-то очень круглые суммы. Как сделать с копейками?
знаю, что можно вайлом, но по учебнику ещё не дошли же
Всё, снова извините, чёт я туплю, спать пора.
Знания где-то на уровне задачи про студентов (сейчас ей занят).
Из ОП-поста:
>По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
Меня немного смущает 2006 год издания.
С PHP 5.6 можно напрямую оператором конкатенации (точкой), если версия меньше - то в методах классах.
Если ты не знаешь PHP то могу посоветовать начать с его изучения. Или поручить задачу кому-нибудь кто его знает.
Алсо если это какой-то движок то советую посмотреть документацию или погуглтить, наверняка не ты первый кто столкнулся с проблемой и есть решение.
Делаю 13 задачу на Java Script.
https://github.com/tokotun/JS/blob/master/lesson_13.js#L140
не могу вызвать функцию this[key].getPower()
Всплывает ошибка. TypeError: this[key].getPower is not a function.
Хотя тут возвращается объект PowerLine и функция getPower() у него есть.
Очевидно нужна еще таблица связи кто кому поставил лайк. Там есть ссылка на статью «SQL для начинающих» и в ней рассказывается про виды связей.
> если задача решается в 2 джойна, должно быть еще 2 таблицы.
Ну я не против если ты ее в 1 джойн решишь :) К тому же таблицы можно джойнить сами на себя.
>>492509
да. Для начала сделай простую версию, вывести 5 самых популярных пользователей.
>>492583
> не могу вызвать функцию this[key].getPower()
> Всплывает ошибка. TypeError: this[key].getPower is not a function.
for .. in перебирает не только свойства объекта (0, 1, 2 ...) но и свойства прототипа. А у твоего объекта прототип это объект PowerLines.protoype и у него есть свойство sellPower:
PowerLines.prototype.sellPower = ...
Вот тут это описано: https://learn.javascript.ru/prototype#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-hasownproperty
Прототипы это очень важная тема, надо с ними разобраться.
Также я не советую делать объект-имитацию массива. Луше использовать настоящий массив:
this.lines = [];
this.lines.push(powerLine1);
Так как у массива в отличие от твоей имитации есть свойства вроде length и методы вроде slice (хотя теоритически ты бы мог унследоваться от Array, но я не уверен что это будет работать. Расширять встроенные объекты в JS сложно и чревато подводными камнями).
> ElectricGrid.prototype.setElectricGrid = function(powerhouses, solarPanels, houses, powerLines){
Старайся не делать такую функции. На практике более удобно работать с функциями вроде addPowerhouse() которой можно добавлять объекты одного вида по одному. Более того, если подумать, эти объекты однотипные и можно сделать универслаьную функцию:
addGridElement(element)
Код тогда может выглядеть так:
var grid = new EGrid();
var house1 = new House(100); // дом из 100 квартир
grid.addElement(house);
....
(разумеется это не значит что именно так надо писать, это просто пример, добавлять можно и циклом и функциями)
И соответственно иметь один общий массив подсоединенных к сети объектов. Я думаю, надо так сделать, тогда мы можем легко например добавить еще несколько видов объектов, не меняя код ElectricGrid — в этом как раз сила ООП.
А, хотя у тебя элементы сети не имеют общего предка. Зря. Ведь у всех этих электростанций и потребителей есть общая вещь: они все подсоединены к сети и генерируют либо потребляют энергию (то есть вносят вклад в энергетический баланс). Я бы заменил Generator на ЭлементСети и унаследовал всех от него.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L20
> for (var key in this.houses) {
> energy -= houses[key].getApartments() * 4;
Вот это ошибка. Сеть не должна знать сколько потребляет квартира, это должен знать объект House и у него должен быть метод getPower (или getPowerConsumption) который вычисляет объем энергии. Я бы вообще сделал у всех один метод, возвращающий вклад в эенергетический баланс, либо положительный, либо отрицательный.
Алсо for ... in надо сопровождать hasOwnproperty.
> alert('Можно продать '+sellPower+' энергии. В результате получим '+money+' денег');
Я бы это убрал из функции. Функция должна возвращать значение с которым мы можем сделать что хотим, а не выводить его.
В общем, я советую тебе показать мне потом еще код, чтобы мы разобрались, правильно ли ты понимаешь идеи ООП.
Очевидно нужна еще таблица связи кто кому поставил лайк. Там есть ссылка на статью «SQL для начинающих» и в ней рассказывается про виды связей.
> если задача решается в 2 джойна, должно быть еще 2 таблицы.
Ну я не против если ты ее в 1 джойн решишь :) К тому же таблицы можно джойнить сами на себя.
>>492509
да. Для начала сделай простую версию, вывести 5 самых популярных пользователей.
>>492583
> не могу вызвать функцию this[key].getPower()
> Всплывает ошибка. TypeError: this[key].getPower is not a function.
for .. in перебирает не только свойства объекта (0, 1, 2 ...) но и свойства прототипа. А у твоего объекта прототип это объект PowerLines.protoype и у него есть свойство sellPower:
PowerLines.prototype.sellPower = ...
Вот тут это описано: https://learn.javascript.ru/prototype#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-hasownproperty
Прототипы это очень важная тема, надо с ними разобраться.
Также я не советую делать объект-имитацию массива. Луше использовать настоящий массив:
this.lines = [];
this.lines.push(powerLine1);
Так как у массива в отличие от твоей имитации есть свойства вроде length и методы вроде slice (хотя теоритически ты бы мог унследоваться от Array, но я не уверен что это будет работать. Расширять встроенные объекты в JS сложно и чревато подводными камнями).
> ElectricGrid.prototype.setElectricGrid = function(powerhouses, solarPanels, houses, powerLines){
Старайся не делать такую функции. На практике более удобно работать с функциями вроде addPowerhouse() которой можно добавлять объекты одного вида по одному. Более того, если подумать, эти объекты однотипные и можно сделать универслаьную функцию:
addGridElement(element)
Код тогда может выглядеть так:
var grid = new EGrid();
var house1 = new House(100); // дом из 100 квартир
grid.addElement(house);
....
(разумеется это не значит что именно так надо писать, это просто пример, добавлять можно и циклом и функциями)
И соответственно иметь один общий массив подсоединенных к сети объектов. Я думаю, надо так сделать, тогда мы можем легко например добавить еще несколько видов объектов, не меняя код ElectricGrid — в этом как раз сила ООП.
А, хотя у тебя элементы сети не имеют общего предка. Зря. Ведь у всех этих электростанций и потребителей есть общая вещь: они все подсоединены к сети и генерируют либо потребляют энергию (то есть вносят вклад в энергетический баланс). Я бы заменил Generator на ЭлементСети и унаследовал всех от него.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L20
> for (var key in this.houses) {
> energy -= houses[key].getApartments() * 4;
Вот это ошибка. Сеть не должна знать сколько потребляет квартира, это должен знать объект House и у него должен быть метод getPower (или getPowerConsumption) который вычисляет объем энергии. Я бы вообще сделал у всех один метод, возвращающий вклад в эенергетический баланс, либо положительный, либо отрицательный.
Алсо for ... in надо сопровождать hasOwnproperty.
> alert('Можно продать '+sellPower+' энергии. В результате получим '+money+' денег');
Я бы это убрал из функции. Функция должна возвращать значение с которым мы можем сделать что хотим, а не выводить его.
В общем, я советую тебе показать мне потом еще код, чтобы мы разобрались, правильно ли ты понимаешь идеи ООП.
Да, она 2006 года и потому немножко устарела. То есть например вместо PEAR сейчас используют Composer, но сам принцип что нужна система управления зависимостями, он актуален. Поменялось пара поколений фремворков. То есть некоторые главы наверно неактуальны. но в общем книга неплохая.
С книгами проблемы такие:
— книги издаются на английском и не все переводятся
— те что переводят могут быть не самыми новыми
— часть из них, рассчитанная на «чайников», пишется теми, кто в PHP сам еле разбирается и сложных вещей никогда не писал. В итоге слепой ведет слепого.
Те книги, что я указал в ОП посте как раз написаны грамотными авторами, но да, они старые, потому не знаю, если у тебя есть еще какие-то варианты, то может стоит выбрать их.
>>492182
> но по учебнику ещё не дошли же
Ты не обязан использовать только то, что описано в учебнике. Лишь бы код был хороший.
По твоему коду, посмотри внизу ошибка:
> PHP Notice: Undefined variable: month in /home/cskChx/prog.php on line 9
Ты обращаешься к несуществующей еще переменной $month. Вот тут: $month++ в первый раз переменная еще не существует. Надо присвоить начальное ей значение, ноль например.
Считает неправильно:
> softBankTotal: 62156.779757131 руб.
должно быть около 61270
> $sum = $sum × $percent + $comm;
Я советую убрать это из заголовка цикла так как это достаточно сложное условие и лучше написать его внутрь цикла. Тогда и копия этого условия не нужна будет.
Ну и вместо того чтобы уходить в минус, луше наверно проверять чему равен остаток суммы и если он маленький, платить его а не 5000.
Да, она 2006 года и потому немножко устарела. То есть например вместо PEAR сейчас используют Composer, но сам принцип что нужна система управления зависимостями, он актуален. Поменялось пара поколений фремворков. То есть некоторые главы наверно неактуальны. но в общем книга неплохая.
С книгами проблемы такие:
— книги издаются на английском и не все переводятся
— те что переводят могут быть не самыми новыми
— часть из них, рассчитанная на «чайников», пишется теми, кто в PHP сам еле разбирается и сложных вещей никогда не писал. В итоге слепой ведет слепого.
Те книги, что я указал в ОП посте как раз написаны грамотными авторами, но да, они старые, потому не знаю, если у тебя есть еще какие-то варианты, то может стоит выбрать их.
>>492182
> но по учебнику ещё не дошли же
Ты не обязан использовать только то, что описано в учебнике. Лишь бы код был хороший.
По твоему коду, посмотри внизу ошибка:
> PHP Notice: Undefined variable: month in /home/cskChx/prog.php on line 9
Ты обращаешься к несуществующей еще переменной $month. Вот тут: $month++ в первый раз переменная еще не существует. Надо присвоить начальное ей значение, ноль например.
Считает неправильно:
> softBankTotal: 62156.779757131 руб.
должно быть около 61270
> $sum = $sum × $percent + $comm;
Я советую убрать это из заголовка цикла так как это достаточно сложное условие и лучше написать его внутрь цикла. Тогда и копия этого условия не нужна будет.
Ну и вместо того чтобы уходить в минус, луше наверно проверять чему равен остаток суммы и если он маленький, платить его а не 5000.
Нельзя по моему, так как это свойство класса и оно должно иметь констатное начальное значение не зависящее от переменных.
Оп, помоги с задачей про граморных нацистов.
А что не так? Я пока код прокомментирую:
> [a|(но)]
это не то что ты думаешь. Это значит «любой из символов a, |, (, н, о, )»
(если ты понимаешь английский то можешь вписать свою регулярку на сайте regex101 и он справа объяснит что значит каждый символ в ней. Не забудь только что там бекслеш пишется один раз вроде \s а не два).
> [,;:!?]\\S
Это сработает на конструкцию вроде ??? или !!!. Я бы предусмотрел такое. Также, где точка?
> [^,]\\s
Я бы вписал что может быть любое число пробелов. Также, я бы вписал чуть более сложное условие чтобы не реагировало на такие случаи:
Хорошо. А диск я отдам...
Тут перед «а» стоит точка вместо запятой.
> [a|(но)]\\s
тут я бы добавил условие что после «а» еще может быть знак препинания. Или можно написать
a\\b
где \\b значит граница слова, то есть «с одной стороны стоит буква, с другой не-буква»
Мануал
http://php.net/manual/ru/regexp.reference.escape.php
http://php.net/manual/ru/regexp.reference.character-classes.php
А что не так? Я пока код прокомментирую:
> [a|(но)]
это не то что ты думаешь. Это значит «любой из символов a, |, (, н, о, )»
(если ты понимаешь английский то можешь вписать свою регулярку на сайте regex101 и он справа объяснит что значит каждый символ в ней. Не забудь только что там бекслеш пишется один раз вроде \s а не два).
> [,;:!?]\\S
Это сработает на конструкцию вроде ??? или !!!. Я бы предусмотрел такое. Также, где точка?
> [^,]\\s
Я бы вписал что может быть любое число пробелов. Также, я бы вписал чуть более сложное условие чтобы не реагировало на такие случаи:
Хорошо. А диск я отдам...
Тут перед «а» стоит точка вместо запятой.
> [a|(но)]\\s
тут я бы добавил условие что после «а» еще может быть знак препинания. Или можно написать
a\\b
где \\b значит граница слова, то есть «с одной стороны стоит буква, с другой не-буква»
Мануал
http://php.net/manual/ru/regexp.reference.escape.php
http://php.net/manual/ru/regexp.reference.character-classes.php
я пока переделал с кредитами, да 3900 это не очень точная цифра, но пусть так.
Нет, это неправильное решение. Сумма взята с потолка и если поменять параметры в задаче, она начнет работать неправильно.
Код внутри цикла лучше написать как-то так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
http://ideone.com/oOs4t2
ну теперь то точно как надо с кредитами
http://ideone.com/e4Hr8A
а здесь опять что-то не так. \\b не прокатит, думаю, ибо "а" может быть окружено пробелами
preg_match находит только первое совпадение с регуляркой (и первую ошибку). Надо выводить все, для этого нужна preg_match_all, она описана ниже в уроке. Ну и вывод хоть как-то оформить через echo.
Задача про кредит решена верно.
И скажи что не так.
Задача по ООП Вектор.
https://github.com/Integer64/myTestSite.dev/tree/master/vecktor_OOP
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/autoload.php#L4
> function __autoload($class){
Это способ устаревший и не рекомендуемый (это значит ты никогда не должен его исопльзовать). Проблема в том что такая функция может быть только одна и ты не можешь например подключить библиотеку у которой свой автозагрузчик. Прочти про новый способ:
http://habrahabr.ru/post/136761/
Заметь что он доступен аж с 2006 года, то есть уже 9 лет.
Логика распределенияфайлов по папкам непонятна. Department и Employee это же тоже модели?
Для департаментов, мне кажется, не стоит создавать отдельные классы так как они различаются только названием.
Далее, твой класс Employee не умеет автоматически пересчитывать зарплату. Вот простой тест:
$engineer = new Engineer(1, false);
$oldSalary = $engineer->getPayment();
var_dump($oldSalary); // 200
$engineer->setRank(2);
$newSalary = $engineer->getPayment();
var_dump($newSalary); // Упс, зарплата не повысилась, по-прежнему 200
assert($newSalary > $oldSalary); // условие не выполняется
Это плохо, твой класс ведет себя не так как мы ожидаем. Согласись логично ожидать что зарплата увелчится при повышении ранга.
Я советую убрать метод recalculation и рассчитывать зарплату прямо в функции getPayment, тогда она всегда будет актуальной. Аналогично с кофе и бумагами. Иногда результат проще не хранить, а вычислять заново.
Все публичные методы должны возвращать точные и актуальные данные в любой ситуации и не зависеть от порядка вызова или еще чего-то. То есть как бы мы не меняли ранги, и другие свойства, зарплата должна всегда считаться верно. Только при таком подходе мы можем сделать надежную программу.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Department.php#L15
> public function addEmployee($employee)
Здесь нужен тайп хинт
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
> public function deleteEmployee($id){
Это непригодная для использования функция. Где я возьму этот id? Я думаю, функция должна принимать на вход сотрудника который подлежит увольнению.
Найти его в массиве легко с помощью array-search, не забудь только про флаг задающий точное сравнение.
> unset($this->$arr[$id]);
Что это? $this->$arr ?
> protected $wageCosts;
> protected $coffeeConsumption;
> protected $paperConsumption;
> protected $averageDischarge;
Я думаю что эти свойства незачем хранить постоянно так как они устаревают при добавлении/убавлении сотрудника, и посчитать их заново несложно. То есть лучше сделать не так:
> $this->wageCosts = $wageCosts;
а так:
return $wageCosts;
Метод SetTitle можно не делать, если переименование не предполагается (но если он есть, пусть будет, вдруг пригодится).
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/models/Vecktor.php#L95
Нужен тайп хинт
> for($i = 0;$i < $length; $i++){
> $space = $space." " ;
Используй str_repeat вместо цикла
А так, вообще для начинающего неплохо, хотя у меня есть подозрения что ты просто учел ошибки других анонов и может быть посмотрел их код.
Также, давай проверим гибок ли твой код? Способен ли он подстраиваться под постоянно меняющиеся требования заказчика (а именно для этого и нужна хорошая архитектура)?
Вот тебе новые требования к задаче:
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/autoload.php#L4
> function __autoload($class){
Это способ устаревший и не рекомендуемый (это значит ты никогда не должен его исопльзовать). Проблема в том что такая функция может быть только одна и ты не можешь например подключить библиотеку у которой свой автозагрузчик. Прочти про новый способ:
http://habrahabr.ru/post/136761/
Заметь что он доступен аж с 2006 года, то есть уже 9 лет.
Логика распределенияфайлов по папкам непонятна. Department и Employee это же тоже модели?
Для департаментов, мне кажется, не стоит создавать отдельные классы так как они различаются только названием.
Далее, твой класс Employee не умеет автоматически пересчитывать зарплату. Вот простой тест:
$engineer = new Engineer(1, false);
$oldSalary = $engineer->getPayment();
var_dump($oldSalary); // 200
$engineer->setRank(2);
$newSalary = $engineer->getPayment();
var_dump($newSalary); // Упс, зарплата не повысилась, по-прежнему 200
assert($newSalary > $oldSalary); // условие не выполняется
Это плохо, твой класс ведет себя не так как мы ожидаем. Согласись логично ожидать что зарплата увелчится при повышении ранга.
Я советую убрать метод recalculation и рассчитывать зарплату прямо в функции getPayment, тогда она всегда будет актуальной. Аналогично с кофе и бумагами. Иногда результат проще не хранить, а вычислять заново.
Все публичные методы должны возвращать точные и актуальные данные в любой ситуации и не зависеть от порядка вызова или еще чего-то. То есть как бы мы не меняли ранги, и другие свойства, зарплата должна всегда считаться верно. Только при таком подходе мы можем сделать надежную программу.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Department.php#L15
> public function addEmployee($employee)
Здесь нужен тайп хинт
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
> public function deleteEmployee($id){
Это непригодная для использования функция. Где я возьму этот id? Я думаю, функция должна принимать на вход сотрудника который подлежит увольнению.
Найти его в массиве легко с помощью array-search, не забудь только про флаг задающий точное сравнение.
> unset($this->$arr[$id]);
Что это? $this->$arr ?
> protected $wageCosts;
> protected $coffeeConsumption;
> protected $paperConsumption;
> protected $averageDischarge;
Я думаю что эти свойства незачем хранить постоянно так как они устаревают при добавлении/убавлении сотрудника, и посчитать их заново несложно. То есть лучше сделать не так:
> $this->wageCosts = $wageCosts;
а так:
return $wageCosts;
Метод SetTitle можно не делать, если переименование не предполагается (но если он есть, пусть будет, вдруг пригодится).
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/models/Vecktor.php#L95
Нужен тайп хинт
> for($i = 0;$i < $length; $i++){
> $space = $space." " ;
Используй str_repeat вместо цикла
А так, вообще для начинающего неплохо, хотя у меня есть подозрения что ты просто учел ошибки других анонов и может быть посмотрел их код.
Также, давай проверим гибок ли твой код? Способен ли он подстраиваться под постоянно меняющиеся требования заказчика (а именно для этого и нужна хорошая архитектура)?
Вот тебе новые требования к задаче:
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
Спасибо ОП. Учту замечания и исправлю.Честно решение других не смотрел, просто посмотрел курсы с гикбрейн))
Кстати для удобного хранения объектв (сотрудников например) есть специальный класс SplObjectStorage который позволяет добавлять и удалять объекты из него: http://php.net/manual/ru/class.splobjectstorage.php
При огромном числе объектов он будет быстрее так как при увольнении поиск сотрудника в массиве занимает O(N), то есть мы обходим массив чтобы найти под каким ключом хранится сотрудник. Увольнение всех сотрудников требует повторить эту операцию N раз и имеет сложность примерно O(N^2). В то время как в SplObjectSTorage увольнение делается за O(1). Разница правда будет заметна на тысячах и более сотрудников и частых увольнениях.
https://github.com/nsdvw/file-sharing
Из тех слабых мест, которые я сам вижу, но не знаю, как исправить:
1) После того, как файл загружен, нужно вывести пользователю сообщение об успешном завершении этой операции.
Логично завести у какого-то объекта свойства типа flashMessage и errorMessage, передавать их в шаблон. Но я не знаю, какому объекту.
2) Из предыдущего пункта вытекает, что хотелось бы таки иметь объект контроллера.
Слим позволяет обойтись без него, используя в качестве экшенов колл-бек функции
$app->get('/url', function(){
...
//много кода
...
});
Но это неудобно, потому что функции могут быть большими, некрасиво. Плюс мне может понадобится заменить экшен на совершенно другой. Логично таки повыносить все эти анонимные функции в методы какому-то объекту.
Я пробовал, не получаеца. Возможно это связано с тем, что нужно как-то протащить замыкание.
Пробовал так:
$app->get('/url', $controller->actionName use ($app));
Пробовал так:
$app->get('/url', $controller->actionName);
class Controller
{
...
public function actionName() use ($app){}
}
Тоже не работает. Причем ошибки нет, выдает белый экран. Странно.
3) Еще у меня почему-то редирект не срабатывает, после запроса методом пост естественно нужно переправить на гет.
Может я что-то упускаю? header('Location: '. $_SEVER['PHP_SELF'])
4) Ну и конфиги базы и белые массивы mime-типов, которые у меня валяются где-то в методах модели, тоже нужно засунуть куда-то в свойства контроллера. См.пункт 2.
Шаблонизатор смарти оп вроде не котирует, но он единственный из тех что я знаю, твиг чуть попозже выучу. Все равно планирую в следующем месяце уже страдать над симфони.
Я немного запутался со всеми этими путями. Там у меня в коде сплошные __DIR__, скрипт нейм, '../', которые не всегда понимаю куда ведут ввиду того что слим оперирует не путями папок а какими-то левыми маршрутами. Как выцепить НАСТОЯЩИЙ путь? Потому что из-за слима __DIR__ выдает мне не папку, где лежит файл скрипта, а фейковый путь маршрута.
Да, и как бы сделать ссылку именно на скачивание? Если указать прямой путь к файлу, браузер пытается его открыть. Если это картинка и видео, конечно. Что не всегда желаемо.
https://github.com/nsdvw/file-sharing
Из тех слабых мест, которые я сам вижу, но не знаю, как исправить:
1) После того, как файл загружен, нужно вывести пользователю сообщение об успешном завершении этой операции.
Логично завести у какого-то объекта свойства типа flashMessage и errorMessage, передавать их в шаблон. Но я не знаю, какому объекту.
2) Из предыдущего пункта вытекает, что хотелось бы таки иметь объект контроллера.
Слим позволяет обойтись без него, используя в качестве экшенов колл-бек функции
$app->get('/url', function(){
...
//много кода
...
});
Но это неудобно, потому что функции могут быть большими, некрасиво. Плюс мне может понадобится заменить экшен на совершенно другой. Логично таки повыносить все эти анонимные функции в методы какому-то объекту.
Я пробовал, не получаеца. Возможно это связано с тем, что нужно как-то протащить замыкание.
Пробовал так:
$app->get('/url', $controller->actionName use ($app));
Пробовал так:
$app->get('/url', $controller->actionName);
class Controller
{
...
public function actionName() use ($app){}
}
Тоже не работает. Причем ошибки нет, выдает белый экран. Странно.
3) Еще у меня почему-то редирект не срабатывает, после запроса методом пост естественно нужно переправить на гет.
Может я что-то упускаю? header('Location: '. $_SEVER['PHP_SELF'])
4) Ну и конфиги базы и белые массивы mime-типов, которые у меня валяются где-то в методах модели, тоже нужно засунуть куда-то в свойства контроллера. См.пункт 2.
Шаблонизатор смарти оп вроде не котирует, но он единственный из тех что я знаю, твиг чуть попозже выучу. Все равно планирую в следующем месяце уже страдать над симфони.
Я немного запутался со всеми этими путями. Там у меня в коде сплошные __DIR__, скрипт нейм, '../', которые не всегда понимаю куда ведут ввиду того что слим оперирует не путями папок а какими-то левыми маршрутами. Как выцепить НАСТОЯЩИЙ путь? Потому что из-за слима __DIR__ выдает мне не папку, где лежит файл скрипта, а фейковый путь маршрута.
Да, и как бы сделать ссылку именно на скачивание? Если указать прямой путь к файлу, браузер пытается его открыть. Если это картинка и видео, конечно. Что не всегда желаемо.
Запутался с синтаксисом гитигнора.
Строка, которая начинается с восклицательного знака, позволяет внести исключение из правил, ведь так? Но почему у меня игнорируется .htaccess в папке загрузок, который я специально прописал?
.
~
upload/
templates_c/
vendor/
! upload/.htaccess
_ _ DIR _ _ всегда возвращает папку в которой находится текущий скрипт (не index.php а текущий) и Слим тут не при чем.
Сообщение об ошибки загрузки проще всего показать, явно передав переменную с текстом в смарти. При ошибочной обработке формы ты не должен редиректить, а стоит показать эту форму с сообщением об ошибке. Если там были введены какие-то данные вроде комментария, их надо вывести в форме.
Вот урок на эту тему: https://github.com/codedokode/pasta/blob/master/forms.md
flash-сообщения используются когда нам надо показать сообщение на другой странице, например после редиректа. Они используют куки либо сессию и мне не очень нравятся, так как несколько вкладок браузера разделяют общую сессию и куки и в flash сообющениях нет никакой защиты от ошибок. Например если у тебя загружается несколько вкладок и одна из них создает flash сообщение, оно может показаться в другой. Я люблю уведомления делать через get-параметры вроде такого:
/users?notify=saved // выводит сообщение что данные сохранены
> Причем ошибки нет, выдает белый экран.
У тебя просто отключен вывод ошибок на экран.
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Проверить, работает ли вывод ошибок, можно запустив скрипт содержающий обращение к несуществующей переменной вроде echo $sdgasdad; и проверив, выведется ошибка или нет. Если все верно, то должна вывестись.
> Шаблонизатор смарти оп вроде не котирует, но он единственный из тех что я знаю
Он довольно старый и не умеет делать автоескейпинг, не умеет в наследование шаблонов, так что советую изучить твиг. После смарти ты его за день освоишь.
Более того, в исходниках смарти есть довольно сомнительные и костыльные решения.
> Если указать прямой путь к файлу, браузер пытается его открыть.
Надо добавлять заголовок Content-Disposition: attachment
> https://github.com/nsdvw/file-sharing/blob/master/my_autoloader.php#L3
> require __DIR__ . '/classes/' . $class . '.php';
Надо проверять если такой файл перед ключением. Иначе
class_exists('abcdef')
уронит твою программу с фатальной ошибкой.
Алсо, ты используешь композер и это значит что автозагрузчик писать не надо. Просто сделай чтобы твои имена файлов соответсвовали PSR-0 или PSR-4 и пропиши автозагрузку в composer.json (и вызови composer dump-autoload для перегенерации файла autoload).
Композер поддерживает PSR-0, PSR-4, подключение файлов явно и classmap для старых приложений.
маунал на англ: https://getcomposer.org/doc/04-schema.md#autoload
статья (старенькая): http://habrahabr.ru/post/149678/
http://onedev.net/post/176
http://zenwalker.me/blog/php-psr-0-vs-psr-4.html
В общем, перестань писать свои автозагрузчики.
> $type = $_FILES['upload']['type']['file1'];
Я советую не использовать MIME от браузера так как он может быть неточным и браузер может не знать о каких-то типах файлов. Проверяй либо расширение либо содержимое.
Также, хотелось бы возможность загрузки любых файлов.
> \t$finfo = new finfo(FILEINFO_MIME_TYPE);
Удобнее определять информацию о файле только один раз при закачке и сохранять в базе. Ведь просматривают страницу файла чаще чем загружают новые.
Насчет работы с БД, какой паттерн ты использовал? Урок https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md читал?
> $dbh = new PDO($this->db_config['conn'], $this->db_config['user'],
> $this->db_config['pass']);
Не надо так, соединени с БД лучше создавать один раз и не в классе работы с БД и передавать например через конструктор или как-то еще.
Я думаю, читать конфиг и создавать PDO лучше всего в index.php, используя возможности Singleton в Слиме: http://docs.slimframework.com/di/overview/
То есть ты создаешь «сервис» предоставляющий соединение с БД через
$app->container->singleton('db', function () { .... });
> https://github.com/nsdvw/file-sharing/blob/master/db.sql#L15
> author`s
Кавычку можно вставить как \'
> FOREIGN KEY (author_id) REFERENCES user (id),
Почему ON UPDATE/DELETE не прописал?
При сохранении файла лучше бы сначала копировать файл, а потом сохранять в базу чтобы не было такого что запись указваает на несущесвующий файл. Но тебе нужен id. Я советую обернуть операцию вставки в транзакцию и коммитить транзакцию только после успешного копирования файла.
> https://github.com/nsdvw/file-sharing/blob/master/index.php#L29
Что тут за пустой else? Что произойдет в этом случае?
Также, при загрузке лучше провеять поле error у файла через сравнение if $error == UPLOAD_ERROR_OK или как-то так.
> $app->get('/view/:id', function ($id) use ($app) {
Нет проверки что такой файл сущенствует. При неправильном id надо вызывать слимовский notFound (кстати вид этой страницы ты можешь переопределить).
_ _ DIR _ _ всегда возвращает папку в которой находится текущий скрипт (не index.php а текущий) и Слим тут не при чем.
Сообщение об ошибки загрузки проще всего показать, явно передав переменную с текстом в смарти. При ошибочной обработке формы ты не должен редиректить, а стоит показать эту форму с сообщением об ошибке. Если там были введены какие-то данные вроде комментария, их надо вывести в форме.
Вот урок на эту тему: https://github.com/codedokode/pasta/blob/master/forms.md
flash-сообщения используются когда нам надо показать сообщение на другой странице, например после редиректа. Они используют куки либо сессию и мне не очень нравятся, так как несколько вкладок браузера разделяют общую сессию и куки и в flash сообющениях нет никакой защиты от ошибок. Например если у тебя загружается несколько вкладок и одна из них создает flash сообщение, оно может показаться в другой. Я люблю уведомления делать через get-параметры вроде такого:
/users?notify=saved // выводит сообщение что данные сохранены
> Причем ошибки нет, выдает белый экран.
У тебя просто отключен вывод ошибок на экран.
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Проверить, работает ли вывод ошибок, можно запустив скрипт содержающий обращение к несуществующей переменной вроде echo $sdgasdad; и проверив, выведется ошибка или нет. Если все верно, то должна вывестись.
> Шаблонизатор смарти оп вроде не котирует, но он единственный из тех что я знаю
Он довольно старый и не умеет делать автоескейпинг, не умеет в наследование шаблонов, так что советую изучить твиг. После смарти ты его за день освоишь.
Более того, в исходниках смарти есть довольно сомнительные и костыльные решения.
> Если указать прямой путь к файлу, браузер пытается его открыть.
Надо добавлять заголовок Content-Disposition: attachment
> https://github.com/nsdvw/file-sharing/blob/master/my_autoloader.php#L3
> require __DIR__ . '/classes/' . $class . '.php';
Надо проверять если такой файл перед ключением. Иначе
class_exists('abcdef')
уронит твою программу с фатальной ошибкой.
Алсо, ты используешь композер и это значит что автозагрузчик писать не надо. Просто сделай чтобы твои имена файлов соответсвовали PSR-0 или PSR-4 и пропиши автозагрузку в composer.json (и вызови composer dump-autoload для перегенерации файла autoload).
Композер поддерживает PSR-0, PSR-4, подключение файлов явно и classmap для старых приложений.
маунал на англ: https://getcomposer.org/doc/04-schema.md#autoload
статья (старенькая): http://habrahabr.ru/post/149678/
http://onedev.net/post/176
http://zenwalker.me/blog/php-psr-0-vs-psr-4.html
В общем, перестань писать свои автозагрузчики.
> $type = $_FILES['upload']['type']['file1'];
Я советую не использовать MIME от браузера так как он может быть неточным и браузер может не знать о каких-то типах файлов. Проверяй либо расширение либо содержимое.
Также, хотелось бы возможность загрузки любых файлов.
> \t$finfo = new finfo(FILEINFO_MIME_TYPE);
Удобнее определять информацию о файле только один раз при закачке и сохранять в базе. Ведь просматривают страницу файла чаще чем загружают новые.
Насчет работы с БД, какой паттерн ты использовал? Урок https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md читал?
> $dbh = new PDO($this->db_config['conn'], $this->db_config['user'],
> $this->db_config['pass']);
Не надо так, соединени с БД лучше создавать один раз и не в классе работы с БД и передавать например через конструктор или как-то еще.
Я думаю, читать конфиг и создавать PDO лучше всего в index.php, используя возможности Singleton в Слиме: http://docs.slimframework.com/di/overview/
То есть ты создаешь «сервис» предоставляющий соединение с БД через
$app->container->singleton('db', function () { .... });
> https://github.com/nsdvw/file-sharing/blob/master/db.sql#L15
> author`s
Кавычку можно вставить как \'
> FOREIGN KEY (author_id) REFERENCES user (id),
Почему ON UPDATE/DELETE не прописал?
При сохранении файла лучше бы сначала копировать файл, а потом сохранять в базу чтобы не было такого что запись указваает на несущесвующий файл. Но тебе нужен id. Я советую обернуть операцию вставки в транзакцию и коммитить транзакцию только после успешного копирования файла.
> https://github.com/nsdvw/file-sharing/blob/master/index.php#L29
Что тут за пустой else? Что произойдет в этом случае?
Также, при загрузке лучше провеять поле error у файла через сравнение if $error == UPLOAD_ERROR_OK или как-то так.
> $app->get('/view/:id', function ($id) use ($app) {
Нет проверки что такой файл сущенствует. При неправильном id надо вызывать слимовский notFound (кстати вид этой страницы ты можешь переопределить).
> Но почему у меня игнорируется .htaccess в папке загрузок, который я специально прописал?
Пробел не нужен после !
Еще ты не загрузил файл .htaccess
Еще у тебя можно открыть например URL /classes и увидеть список файлов (если в Апаче включен показ содержимого папки). Более того, можно прочесть конфиг по ссылке /classes/config.txt.
Как бороться? Лучший способ — не класть в веб-папку ничего что ты не хочешь показывать людям. То есть выносишь код и конфиги за пределы веб-папки, чтобы было так:
/classes
/views
/public
/public/index.php
/public/css
И настраиваешь Апач чтобы корень сайта был в public. Это лучший способ, все нормальные пацаны так делают.
Второй вариант: в htaccess закрываем доступ к папкам с кодом через Deny from all. Минус в том что можно добавить новую папку и забыть ее закрыть. Аналогично можно прописать эти настройки в конфиге Апача. Это способ похуже.
Третий вариант: кладем в папки с кодом index.html с текстом «Nothing here, officer» (защита от просмотра папки) и делаем конфиг в php-файле. Это конечно самый слабый способ. К тому же ты не должен ничего класть в vendor, и это значит что все файлы в vendor доступны для вызова снаружи. А что если там есть php-файл позволяющий что-то сделать нехорошее?
Кстати, написав это, мне пришла мысль в голову проверить, а как с просмотром директорий на других сайтах? Я набрал в гугле
inurl:/vendor/ index of
И вот что мы видим:
http://www.dadack.com/vendor/
http://www.brunrice.com/vendor/
http://www.spouseup.com/app/
http://swingtop-open.com/vendor/
http://www.mariby.com/vendor/
не знаю, можно ли это использовать как-то в плохих целях, но все же не стоит показывать файлы всем желающим.
Алсо баг с открытыми папками систем контроля версий, который я видел много лет назад, до сих пор актуален:
http://sunshinemanagement.net/.git/
http://redfabriq.com/.git/
Из этой папки можно выкачать весь код сайта ( но не делай так без разрешения, это может быть нарушением закона).
Еще ты не загрузил файл .htaccess
Еще у тебя можно открыть например URL /classes и увидеть список файлов (если в Апаче включен показ содержимого папки). Более того, можно прочесть конфиг по ссылке /classes/config.txt.
Как бороться? Лучший способ — не класть в веб-папку ничего что ты не хочешь показывать людям. То есть выносишь код и конфиги за пределы веб-папки, чтобы было так:
/classes
/views
/public
/public/index.php
/public/css
И настраиваешь Апач чтобы корень сайта был в public. Это лучший способ, все нормальные пацаны так делают.
Второй вариант: в htaccess закрываем доступ к папкам с кодом через Deny from all. Минус в том что можно добавить новую папку и забыть ее закрыть. Аналогично можно прописать эти настройки в конфиге Апача. Это способ похуже.
Третий вариант: кладем в папки с кодом index.html с текстом «Nothing here, officer» (защита от просмотра папки) и делаем конфиг в php-файле. Это конечно самый слабый способ. К тому же ты не должен ничего класть в vendor, и это значит что все файлы в vendor доступны для вызова снаружи. А что если там есть php-файл позволяющий что-то сделать нехорошее?
Кстати, написав это, мне пришла мысль в голову проверить, а как с просмотром директорий на других сайтах? Я набрал в гугле
inurl:/vendor/ index of
И вот что мы видим:
http://www.dadack.com/vendor/
http://www.brunrice.com/vendor/
http://www.spouseup.com/app/
http://swingtop-open.com/vendor/
http://www.mariby.com/vendor/
не знаю, можно ли это использовать как-то в плохих целях, но все же не стоит показывать файлы всем желающим.
Алсо баг с открытыми папками систем контроля версий, который я видел много лет назад, до сих пор актуален:
http://sunshinemanagement.net/.git/
http://redfabriq.com/.git/
Из этой папки можно выкачать весь код сайта ( но не делай так без разрешения, это может быть нарушением закона).
Я не понимаю, почему на ошибку с "а" не находит, но аналогичную с "но" видит?
После нахождения совпадения поиск продолжается со следующего символа.
Слово «зделал» захвачено регуляркой и после его нахождения поиск продолжается начиная с пробела. То есть движок регулярок видит такой текст:
_а.
А у тебя в регулярке написано что перед «а» должна быть буква.
Чтобы решить эту проблему тебе нужны утверждения, которые могут заглядывать назад: http://php.net/manual/ru/regexp.reference.assertions.php
Либо же сделать для каждого правила свою регулярку и вызывать preg_match_all несколько раз.
http://ideone.com/3PNTdo
> function sequence(start=0, step=1) {
Значения по умолчанию по моему есть только в новом яваскрипте (ES6?), а в старом надо писать штуки вроде
start = start || 0;
https://learn.javascript.ru/function-basics#%D0%B0%D1%80%D0%B3%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B-%D0%BF%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB%D1%87%D0%B0%D0%BD%D0%B8%D1%8E
> prog.js:13:0 ReferenceError: console is not defined
На ideone видимо console.log не поддерживается
> return function(step){
Вот тут ошибка. Ты возвращаешь функцию, которая принимает аргумент step. Но при вызове мы ничего не передаем:
> сonsole.log(generator());
Соответвтенно функция, которую ты возвращаешь, должна быть без аргументов, так как их никто не передаст.
Но это и не надо. Переменные внешней функции будут доступны во внутренней, так как она захватывает ссылки на них при создании. Это (функция + захваченные переменные) называется замыкание: https://learn.javascript.ru/closures
Про замыкания еще написаго у меня тут вверху: https://gist.github.com/codedokode/ce30e7a036f18f416ae0#%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D0%B8-%D0%B7%D0%B0%D0%BC%D1%8B%D0%BA%D0%B0%D0%BD%D0%B8%D1%8F
Замыкания важная тема и надо в ней разобраться.
Антоны, как добавить подсветку синтаксиса кода на свой сайт?
https://github.com/V3N0m21/StudentList
При подстановке данных в URL надо обрабатывать их через urlencode чтобы спецсимволы кодировались процентным кодированием ( https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ).
А как тогда работать с поиском по базе?
прописал на входе urlencode для $_GET вхождений, при обработке запроса в базе дописал urldecode, но при перелистывании страниц результатов уже вместо буквы А в базе ищет
%25D0%25B0
Прописал ради интереса двойной urldecode - для второго перелистывания работает, если ещё раз сменить страницу - снова в поиске переменная с кодировкой. Есть алгоритм какой нибудь?
Вот отрывок кода
http://ideone.com/3aQiHt
Я так понял, что при каждой обработке гет-запроса он снова энкодится, как то можно остановить это?
>Ты должен разобраться в этой теме. Чтобы помочь тебе, вот мини-задача:
Сделай страницу с формой из textarea и кнопки отправки. Никакого оформления и CSS не требуется, просто черный текст на белом фоне. При вводе любого текста и нажатия кнопки текст должен появиться внизу под textarea. Текст должен точно соответствовать введенному, корректно отображать все символы, включая пробелы и переводы строк (тут тебе поможет тег pre), точно так как их ввел пользователь.
http://ideone.com/U3JTto
> прописал на входе urlencode для $_GET вхождений,
Не надо делать это на входе. Это надо делать только когда ты собираешь URL из кусочков. urlencode используется только для подставновки данных в URL и ее не надо использовать в других случаях, например при поиске в базе или где-то еще.
Также не надо делть urlencode если ты передаешь данные в функцию http_build_query, она кодирует их сама, а в твоем случае получается двойное кодирование. urlencode испольузется только когда ты руками собираешь ссылку:
$link = 'index.php?a=' . urlencode($a);
>>493241
Маленькое замечание: вместо input надо сделать textarea чтобы можно было ввести текст из нескольких строк и проверить работают ли переносы строк.
Если открыть твой файл то вместо букв отображаются закорючки вроде
> Ваш Текст:
Это потому что у тебя нет тега <meta charset="..."> в начале файла который говорит браузеру в какой он кодировке.
У тебя не сохраняются пробелы в тексте. Если ввести:
a (4 пробела) b (4 пробела) c
То они выводятся через один пробел. Это потому что в HTML любое число пробелов и переводов строк воспринимается как один пробел. Чтобы это исправить, надо либо использовать тег pre либо css-свойство white-space ( http://htmlbook.ru/css/white-space ) которые позволяют изменить это.
Также, твоя задача сыплет ошибками. Включен ли у тебя вывод ошибок? Ты их видишь? Если просто открыть твой файл, то выводятся такие ошибки:
> Notice: Undefined index: text in D:\www\tester\tests\escape.php on line 6
> Notice: Undefined index: text in D:\www\tester\tests\escape.php on line 7
Это из-за того что я просто открыл файл и массив _GET пустой. Соответственно обращение $_GET['text'] приводит к ошибке.
Если ты видишь ошибки то надо их исправить. Если ты не видишь этих ошибок то тебе надо включить вывод ошибок.
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Другие конструкции, которые я проверил, выводятся верно. Проблема пока только в пробелах и в кодировке.
Ну и наконец, в коде ты делаешь лишние преобразования. Вот например:
> $text = urlencode($_POST['text']);
> echo "Ваш текст из формы:".htmlspecialchars(urldecode($text));
какой смысл сначала закодировать спецсимволы чтобы на следующей строке их раскодировать назад? Я думаю, urlencode/urldecode тут надо убрать. urlencode нужен только когда ты вставляешь данные в ссылку, так:
$link = 'index.php?a=' . urlencode($a);
Если ты используешь http_build_query то делать это не надо, она сама это делает. А так как ты делаешь urlencode то у тебя данные в ссылке дважды закодированы. Например для строки «@@» получается ссылка:
http://tester/tests/escape.php?text=%2540%2540
хотя достаточно закодировать символ @ один раз чтобы получилось
http://tester/tests/escape.php?text=%40%40
Как видишь, твоя программа сначала превращает @ в %40 c помощью urlencode, а потом второй раз, превращает % в %25 и получается %2540. Ну и соответственно ты раскодируешь этот текст обратно 2 раза из-за этого (первый раз это делает PHP при заполнении $_GET, второй раз ты через urldecode).
В общем, убери двойное кодирование символов для ссылки.
> прописал на входе urlencode для $_GET вхождений,
Не надо делать это на входе. Это надо делать только когда ты собираешь URL из кусочков. urlencode используется только для подставновки данных в URL и ее не надо использовать в других случаях, например при поиске в базе или где-то еще.
Также не надо делть urlencode если ты передаешь данные в функцию http_build_query, она кодирует их сама, а в твоем случае получается двойное кодирование. urlencode испольузется только когда ты руками собираешь ссылку:
$link = 'index.php?a=' . urlencode($a);
>>493241
Маленькое замечание: вместо input надо сделать textarea чтобы можно было ввести текст из нескольких строк и проверить работают ли переносы строк.
Если открыть твой файл то вместо букв отображаются закорючки вроде
> Ваш Текст:
Это потому что у тебя нет тега <meta charset="..."> в начале файла который говорит браузеру в какой он кодировке.
У тебя не сохраняются пробелы в тексте. Если ввести:
a (4 пробела) b (4 пробела) c
То они выводятся через один пробел. Это потому что в HTML любое число пробелов и переводов строк воспринимается как один пробел. Чтобы это исправить, надо либо использовать тег pre либо css-свойство white-space ( http://htmlbook.ru/css/white-space ) которые позволяют изменить это.
Также, твоя задача сыплет ошибками. Включен ли у тебя вывод ошибок? Ты их видишь? Если просто открыть твой файл, то выводятся такие ошибки:
> Notice: Undefined index: text in D:\www\tester\tests\escape.php on line 6
> Notice: Undefined index: text in D:\www\tester\tests\escape.php on line 7
Это из-за того что я просто открыл файл и массив _GET пустой. Соответственно обращение $_GET['text'] приводит к ошибке.
Если ты видишь ошибки то надо их исправить. Если ты не видишь этих ошибок то тебе надо включить вывод ошибок.
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Другие конструкции, которые я проверил, выводятся верно. Проблема пока только в пробелах и в кодировке.
Ну и наконец, в коде ты делаешь лишние преобразования. Вот например:
> $text = urlencode($_POST['text']);
> echo "Ваш текст из формы:".htmlspecialchars(urldecode($text));
какой смысл сначала закодировать спецсимволы чтобы на следующей строке их раскодировать назад? Я думаю, urlencode/urldecode тут надо убрать. urlencode нужен только когда ты вставляешь данные в ссылку, так:
$link = 'index.php?a=' . urlencode($a);
Если ты используешь http_build_query то делать это не надо, она сама это делает. А так как ты делаешь urlencode то у тебя данные в ссылке дважды закодированы. Например для строки «@@» получается ссылка:
http://tester/tests/escape.php?text=%2540%2540
хотя достаточно закодировать символ @ один раз чтобы получилось
http://tester/tests/escape.php?text=%40%40
Как видишь, твоя программа сначала превращает @ в %40 c помощью urlencode, а потом второй раз, превращает % в %25 и получается %2540. Ну и соответственно ты раскодируешь этот текст обратно 2 раза из-за этого (первый раз это делает PHP при заполнении $_GET, второй раз ты через urldecode).
В общем, убери двойное кодирование символов для ссылки.
http://ideone.com/MAgDsD
>PHP Notice: Undefined variable: persent in /home/OZq1Nv/prog.php on line 7
Ошибки внизу читай.
> также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Отображение включено (в опен-сервере активна php-5.4 там в ini включены ошибки но всё равно таких ошибок в браузере я не вижу. Только через лог файл можно видеть мне? или где-то ещё надо что-то включить?
ОП как всегда няша. Объяснил даже больше чем я ожидал.
Теперь соорудил такую структуру.
https://github.com/tokotun/JS/blob/master/lesson_13.html
https://github.com/tokotun/JS/blob/master/lesson_13.js
Что бы ещё тут такого переделать?
Я решал задачи, просто у меня возникли сложности именно с локальным хранилищем. Вот я попытался исправить - http://jsfiddle.net/d4a05n5w/8/
1. Добавил выполнения поиска по локал. хранилищу в цикл.
2. Решил пока отказаться от хранения всех экземпляров класса в массиве.
Напомню краткую суть этой своей задачи - на странице есть список товаров, нужно добавить их в локал.хранилище, которое эмулирует БД на сервере.
Описание моего быдлокода:
\t1. - Создаю класс товара.
\t2. - Создаю объекты товара
\t3. - Создаю ф-цию ObjParse(). Она должна добавлять товар в локальное хранилище
\t\t3.1 - Если товар с заданным ключем есть в локальном хранилище, НЕ добавляем его.
\t\t3.2 - Если нет, задаем его таким образом: В качестве ключа назначаем свойство name объекта, в качестве значения - преобразованные в строку свойства name и price даного объекта.
У меня не срабатывает проверка на наличие этого товара в хранилище. И еще - строка 29, попытка поиска ключа несуществующего товара прерывает работу интерпретатора. И как в таком случае правильно составить условие if в ф-ции ObjParse(), если работа кода прерывается, насколько я понял? Как правильно делать обход по лок. хранилищу? Очень нужно добить эту тему, я исправляю портфолио, за которое меня зачмырили.
select user.*,
count(user_like.id) as likes_given,
count(user_like.to_user) as likes_received
from user_like
left join user using(id)
group by user.id;
То получится подсчет только по поставленным лайкам. А как сделать подсчет для разных колонок? И вообще как потом считать взаимные лайки?
Котаны, подскажите, почему partials не проходит тест. Это по джс задание.
В любом случае, когда выполнил partialAny, то и это заодно получилось.
А простой вариант с топ 5 пользователей ты смог сделать?
> То получится подсчет только по поставленным лайкам. А как сделать подсчет для разных колонок?
В этом и задача, понять как :) Смотри, группировать 2 разными способами нельзя. Группировать можно только один раз. Можно группировать по нескольким колонкам:
GROUP BY a.x, b,y
Но это вряд ли даст то, что тебе надо. Давай подумаем, что мы можем сделать.
Мы можем приджойнить к юзерам таблицу лайков по услоию «поставленные юзером лайки». Тогда мы получаем примерно такую таблицу (до группировки):
кто | кому поставил
Иван | юзер2
Иван | юзер3
Иван | юзер4
Петр | юзер1
Петр | юзер6
...
Сгруппировав эту таблицу по пользователям, мы можем посчитать кто сколько поставил лайков. Аналогично мы можем приджойнить таблицу лайков по условию «от кого получил лайк» и после группировки получим число полученных лайков.
А что будет если мы приджойним таблицу лайков 2 раза по обоим условиям? Мы получим полное декартово произведение, то есть к юзеру будут приджойнены все поставленные им лайци, и каждому будут приджойнены полученные. Допустим юзер1 поставит лайки 2, 3, 4 и получил от 3, 6. Таблица будет выглядеть так:
юзер | кому поставил | от кого получил
юзер1 | 2 | 3
юзер1 | 2 | 6
юзер1 | 3 | 3
юзер1 | 3 | 6
юзер1 | 4 | 3
юзер1 | 4 | 6
Мы получаем все возможные сочетания поставленных и полученных лайков. В данном случае это 2×3 = 6 строчек для юзера1.
Можно ли использовать это для решения задачи? На первый взгляд, нет, тут бессмысленно считать число лайков, оно будет равно 6. Но если почитать мануал про аггрегатные функции тебе может придти в голову мысль: http://phpclub.ru/mysql/doc/group-by-functions.html
Вообще, многие задачи решаются так, что ты сначала все джойнишь, отсеиваешь записи условием, как-то группируешь и считаешь результат. Потому важно это освоить. Я тебе потом еще советую решить задачку про кинотеатр и про имиджборду, они помогут освоить тебе эту технику на хорошем уровне.
> И вообще как потом считать взаимные лайки?
Посмотри на таблицу выше и подумай как в ней найти число взаимных лайков (в данном случае это лайк юзеру 3) Ну и проси подсказку, если что.
Алсо запросы и таблицы хорошо бы постить на sqlfiddle, там сразу виден результат (правда он иногда глючит).
А простой вариант с топ 5 пользователей ты смог сделать?
> То получится подсчет только по поставленным лайкам. А как сделать подсчет для разных колонок?
В этом и задача, понять как :) Смотри, группировать 2 разными способами нельзя. Группировать можно только один раз. Можно группировать по нескольким колонкам:
GROUP BY a.x, b,y
Но это вряд ли даст то, что тебе надо. Давай подумаем, что мы можем сделать.
Мы можем приджойнить к юзерам таблицу лайков по услоию «поставленные юзером лайки». Тогда мы получаем примерно такую таблицу (до группировки):
кто | кому поставил
Иван | юзер2
Иван | юзер3
Иван | юзер4
Петр | юзер1
Петр | юзер6
...
Сгруппировав эту таблицу по пользователям, мы можем посчитать кто сколько поставил лайков. Аналогично мы можем приджойнить таблицу лайков по условию «от кого получил лайк» и после группировки получим число полученных лайков.
А что будет если мы приджойним таблицу лайков 2 раза по обоим условиям? Мы получим полное декартово произведение, то есть к юзеру будут приджойнены все поставленные им лайци, и каждому будут приджойнены полученные. Допустим юзер1 поставит лайки 2, 3, 4 и получил от 3, 6. Таблица будет выглядеть так:
юзер | кому поставил | от кого получил
юзер1 | 2 | 3
юзер1 | 2 | 6
юзер1 | 3 | 3
юзер1 | 3 | 6
юзер1 | 4 | 3
юзер1 | 4 | 6
Мы получаем все возможные сочетания поставленных и полученных лайков. В данном случае это 2×3 = 6 строчек для юзера1.
Можно ли использовать это для решения задачи? На первый взгляд, нет, тут бессмысленно считать число лайков, оно будет равно 6. Но если почитать мануал про аггрегатные функции тебе может придти в голову мысль: http://phpclub.ru/mysql/doc/group-by-functions.html
Вообще, многие задачи решаются так, что ты сначала все джойнишь, отсеиваешь записи условием, как-то группируешь и считаешь результат. Потому важно это освоить. Я тебе потом еще советую решить задачку про кинотеатр и про имиджборду, они помогут освоить тебе эту технику на хорошем уровне.
> И вообще как потом считать взаимные лайки?
Посмотри на таблицу выше и подумай как в ней найти число взаимных лайков (в данном случае это лайк юзеру 3) Ну и проси подсказку, если что.
Алсо запросы и таблицы хорошо бы постить на sqlfiddle, там сразу виден результат (правда он иногда глючит).
Алсо, лишний раз убеждаюсь, что бекэнд это не мое. Насколько мне интересно было изучать JS и jQuery все эти дни и насколько скучно выискивать крупицы полезной информации в куче бесполезной (на данный момент) документации.
Результат выполнения следующих команд на пикрелейтед
print_r($student);
print_r($student->getName());
собственно сам код
http://ideone.com/wIIqYH
1)Есть база Oracle в ней таблица с данными о постах , header , content , author и т.д.
2)Есть view в котором форма для создания нового поста блога с input'ами для всех полей поста.
3)Есть модель, в ней case do-new-entry
Как я понимаю - из инпута с помощью $_POST значение грузится в массив, из него записывается в БД, и затем в обратном порядке .
Поясните как это нормально реализовать
Ну бля, ну скрин же, твой собственный.
У тебя массив с 1 элементом, который является объектом. То есть твой запрос возвращает массив объектов. Если бы был не 1 студент а несколько, то было бы лучше заметно.
>>493714
>>493709
>>493707
Спасибо, сбило то, что там он внутри один был, смотрю и вижу только что объект, не заметил что он внутри массива.
https://github.com/Si0n/register3
>>493047
Все учел, спасибо.
Единственное, хотелось бы уточнить один момент.
Корректно ли называть "контроллером" класс, который возвращает функции?
То есть вида
class Controller
{
public function actionIndex(){ return function() use ($var){...}; }
}
У меня только таким способом получилось вытянуть коллбек функции из параметров методов приложения слима,
то есть вместо
$app->get('/url', function () use ($var){
...
много кода
...
});
в индекс.пхп красивые строки вида
$app->get('/url', $controller->actionIndex());
Но меня смущают круглые скобки. Хотелось
$app->get('/url', $controller->actionIndex);
Но тогда непонятно куда совать замыкание use ($var).
А, можно ведь передать необходимые переменные в конструктор.
Не знаю правда, позволительно ли это с точки зрения паттернов.
Это надо было сделать так:
$app->get('/asdasd', function ($app) {
$app->someController->someAction();
});
Ты только сделал код запутаннее.
Алсо можно еще писать так:
$app->get('/asdasd', array($controller, 'indexAction'));
В PHP есть несколько способов передать ссылку на функцию или метод: http://php.net/manual/ru/language.types.callable.php (на англ., но примеры кода понять можно). Это строка с именем функции или статическиого метода, массив для обычных и статических методов, ну и анонимные функции.
Также, у тебя не должно быть необходимости использовать контроллеры. Слим это микрофреймворк для маленьких сайтов и там будет немного маршрутов и обработчиков. Ну и контроллеры должны быть тонкими, так что нет необходимости их выносить отдельно. Покажи потом свой код, я внимательно посмотрю что ты там сделал.
Может я немного не понятно выразился, надо так что бы один уровень выпадающего меню не перекрывал предыдущий а выпадал сбоку от него.
Вот вроде получилось решить часть задачи (без взаимных лайков) по sql про лайки пользователей: http://sqlfiddle.com/#!9/624c6/3
А вот безуспешная попытка решить задачу до конца: http://sqlfiddle.com/#!9/624c6/1.
Вопрос: я иду в правильном направлении? Или все-таки там есть какой-то трюк с подсчетом взаимных лайков?
https://www.youtube.com/watch?v=zZb98gRrT4Q
Это яваскрипт?
sqlfiddle шатается оп второй ссылке, попробую описать словами: чтобы найти взаимные лайки, я делаю опять таки 2 джойна, но во втором джойне я добавляю дополнительное условие и подсчет немного по-другому идет, но при таком подходе неправильно считается кол-во полученных лайков. Вот код запроса:
SELECT user.*,
COUNT(t1.id) as given_likes,
COUNT(t1.to_user) as received_likes,
COUNT(DISTINCT t2.id) as mutual_likes
FROM user
LEFT JOIN user_like t1 ON t1.id = user.id
LEFT JOIN user_like t2 ON t2.to_user = user.id
AND t1.to_user = t2.id
GROUP BY user.id;
Или это совсем не в ту степь?
Заранее спасибо, оп.
Ты сначала в голове четко сформулируй: что такое взаимный лайк?
Это когда человек поставил кому-то лайк, и от того же самого товарища получил в ответ, правильно да?
Подсказка1: временно убери группировку, увидишь те строки, где кому_поставил = от кого получил.
Подсказка2: select можно делать не только из таблиц, но и в результате каких-то математических вычислений, например.
Колонка "взаимные лайки" у тебя формируется по условию: если (кому поставил = от кого получил, то вернуть единицу, иначе NULL). http://www.mysql.ru/docs/man/Control_flow_functions.html
не оп, если это важно
спасибо
Так вот если способ оптимизировать эту програму?
И почему оно работает не оч?
Смотри, ОП-кун, не решал задачу так долго потому что работа(буду писать под magento) и экзамены.
Итак, разберём функцию которую ты возвращаешь.
>function(){
>\t\tif (count === 0) {
>\t count++;
>\t\t\treturn a;
>\t\t} else {
>\t\t\tcount++;
>\t\t\treturn a+step;
>\t\t}
>\t}
вакаба наверно код сломает
Погляди внимательно эта функция будет всегда возвращать a+step. (кроме первого раза, когда count === 0).
А нужно что бы возвращаемое число увеличивалось.
ну тоесть написать что то вроде
a += step;
return a;
Зачем тебе count не понятно.
Если count просто для того, что бы первый раз выводило на step меньше.
То проще в генераторе перед функцией написать.
a = a - step;
Вместо того что б потом каждый раз запускать проверку на условие.
Ты не положил в репозиторий SQL дамп, а я думаю, его тоже надо проверить, база это часть приложения. Положи дамп, и проследи чтобы там не было команд CREATE USER/CREATE DATABASE/GRANT, а только создание таблиц.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L3
> include_once './views/main.php';
Не надо выводить страницу частями:
- вывести шапку
- выполнить код
- вывести серединку
надо делать так:
- выполнить код
- вывести страницу
Потому что после того как ты начал выводить данные, отправка заголовков (то есть редиректы, выставление куки, старт сессии) перестает работать. Ну и код во втором варианте получается проще и логичнее.
> https://github.com/V3N0m21/StudentList/blob/master/views/main.php#L2
> include './lib/init.php';
шаблон не должен заниматься инициализауцей. Этот инклуд надо вынести отсюда например в index.php и подобные скрипты.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L26
> echo "Success!!";
По моему после echo редирект уже может не сработать, так как нельзя отправлять заголовки если что-то выведено. Ну и писать нет смысла, так как браузер все равно не выведет этот текст.
> foreach ($validation->errors as $error) {
> echo $error . "<br>";
Вывод должен делаться в шаблоне, а не в коде. В твоем коде не должно быть никаких echo. Ну и давай как-нибудь покрасивее сделаем, давай например текст ошибки рядом с полем выводить.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L19
> $email = $data->checkEmail($student->email);
Уникальность емайла можно точно так же проверять валидатором, незачем эту проверку отдельно выносить.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L18
Это слишком длинная строка и ее невозможно читать. Старайся укладывать свои строки в 80 символов и не пиши if в одну строчку, пиши в три, файл не бумага, экономить не требуется.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L35
> if (count($validation->errors) == 0) {
Это лучше сделать методом:
if (!$validation->hasErrors()) { ....
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L27
> header("Location: http://zend.tut/");
тут лучше использовать URL без имени хоста: "Location: /"
Также, надо после редиректа выводить уведомление что данные успешно изменены или студент успешно зарегистрирован. Для этого удобно использовать GET-параметр, например /?notify=saved
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L24
> setcookie('user', $student->pswrd, time()+ 60606024365, '/');
Я думаю, лучше сделать функцию вроде АвторизоватьСтудента или как-то так. Так будет и понятнее и удобнее. Аналогично, проверку залогиненности тоже стоит сделать отдельной функцией.
> pswrd
Переименуй лучше это поле нормально, password, так как это сокращение труждно запомнить и постоянно будешь путаться.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php
Настрой свой редактор на использование 4 пробелов вместо таба, так как код разъезжается. Ну и выравнивание тут сбилось, нет дополнительного отступа внутри if. Ты кстати знаешь что во многих IDE и редакторах можно выделить несколько строк и с помощью Tab/Shift + Tab увеличить или уменьшить отступ?
> $student->pswrd = $student->generatePswrd();
Я думаю логичнее будет если функция generatePswrd сама заполнит это свойство (а, она впрочем так и делает, значит присваивание можно убрать).
> if (isset($_POST['edit']))
Редактирование от регистрации надо отличать не по названию кнопки, а по факту залогиненности (например проверив пустой ли id у студента).
Также, при редактировании ты не проверяешь email на уникальность. Почему? Надо проверять, просто добавь условие WHERE id <> ? чтобы он не ругался на свой же email.
> if(isset($_POST['submit']) || isset($_POST['edit']))
Эту проверку можно заменить на проверку метода: if ($_SERVER['REQUEST_METHOD'] == 'POST')
Тестовые скрипты можно добавить в .gitignore и не грузить в репозиторий: https://git-scm.com/book/ru/v1/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-Git-%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D1%8C-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B9#Игнорирование-файлов
> substr(md5(microtime()),rand(0,26),5)
Это слабый код. Там 16 вариантов символов (0-9, a-f) и всего 5 символов. Это дает нам 16^5 = 1 млн вариантов. Мало того, что такой код реально подобрать, может произойти коллизия, то есть 2 студента получат одинаковый код. Я думаю, нам нужен более надежный код, минимум 16-20 символов.
Также, твой код использует ненадежный источник. Текущее время можно примерно угадать и может быть подобрать этот код (хотя так как возможных кодов всего миллион, проще перебирать их). Нельзя использовать время как замену случайному числу. Надо использовать не md5, а просто сгенерировать N случайных символов с помощью mt_rand. Нет ничего более непредсказуемого, чем просто случайные символы. Если ты делаешь преобразования, то ты скорее всего уменьшаешь число возможных вариантов кода и повышаешь предсказуемость.
> https://github.com/V3N0m21/StudentList/blob/master/index.php#L21
> $current = $_GET['current'];
Тут хорошо бы поставить intval, чтобы проходили только числа.
> https://github.com/V3N0m21/StudentList/blob/master/index.php#L26
> $students = $data->searchStudents($search);
Хорошо бы чтобы при поиске работали постраничное отображение и сортировка
Ты не положил в репозиторий SQL дамп, а я думаю, его тоже надо проверить, база это часть приложения. Положи дамп, и проследи чтобы там не было команд CREATE USER/CREATE DATABASE/GRANT, а только создание таблиц.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L3
> include_once './views/main.php';
Не надо выводить страницу частями:
- вывести шапку
- выполнить код
- вывести серединку
надо делать так:
- выполнить код
- вывести страницу
Потому что после того как ты начал выводить данные, отправка заголовков (то есть редиректы, выставление куки, старт сессии) перестает работать. Ну и код во втором варианте получается проще и логичнее.
> https://github.com/V3N0m21/StudentList/blob/master/views/main.php#L2
> include './lib/init.php';
шаблон не должен заниматься инициализауцей. Этот инклуд надо вынести отсюда например в index.php и подобные скрипты.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L26
> echo "Success!!";
По моему после echo редирект уже может не сработать, так как нельзя отправлять заголовки если что-то выведено. Ну и писать нет смысла, так как браузер все равно не выведет этот текст.
> foreach ($validation->errors as $error) {
> echo $error . "<br>";
Вывод должен делаться в шаблоне, а не в коде. В твоем коде не должно быть никаких echo. Ну и давай как-нибудь покрасивее сделаем, давай например текст ошибки рядом с полем выводить.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L19
> $email = $data->checkEmail($student->email);
Уникальность емайла можно точно так же проверять валидатором, незачем эту проверку отдельно выносить.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L18
Это слишком длинная строка и ее невозможно читать. Старайся укладывать свои строки в 80 символов и не пиши if в одну строчку, пиши в три, файл не бумага, экономить не требуется.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L35
> if (count($validation->errors) == 0) {
Это лучше сделать методом:
if (!$validation->hasErrors()) { ....
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L27
> header("Location: http://zend.tut/");
тут лучше использовать URL без имени хоста: "Location: /"
Также, надо после редиректа выводить уведомление что данные успешно изменены или студент успешно зарегистрирован. Для этого удобно использовать GET-параметр, например /?notify=saved
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L24
> setcookie('user', $student->pswrd, time()+ 60606024365, '/');
Я думаю, лучше сделать функцию вроде АвторизоватьСтудента или как-то так. Так будет и понятнее и удобнее. Аналогично, проверку залогиненности тоже стоит сделать отдельной функцией.
> pswrd
Переименуй лучше это поле нормально, password, так как это сокращение труждно запомнить и постоянно будешь путаться.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php
Настрой свой редактор на использование 4 пробелов вместо таба, так как код разъезжается. Ну и выравнивание тут сбилось, нет дополнительного отступа внутри if. Ты кстати знаешь что во многих IDE и редакторах можно выделить несколько строк и с помощью Tab/Shift + Tab увеличить или уменьшить отступ?
> $student->pswrd = $student->generatePswrd();
Я думаю логичнее будет если функция generatePswrd сама заполнит это свойство (а, она впрочем так и делает, значит присваивание можно убрать).
> if (isset($_POST['edit']))
Редактирование от регистрации надо отличать не по названию кнопки, а по факту залогиненности (например проверив пустой ли id у студента).
Также, при редактировании ты не проверяешь email на уникальность. Почему? Надо проверять, просто добавь условие WHERE id <> ? чтобы он не ругался на свой же email.
> if(isset($_POST['submit']) || isset($_POST['edit']))
Эту проверку можно заменить на проверку метода: if ($_SERVER['REQUEST_METHOD'] == 'POST')
Тестовые скрипты можно добавить в .gitignore и не грузить в репозиторий: https://git-scm.com/book/ru/v1/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-Git-%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D1%8C-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B9#Игнорирование-файлов
> substr(md5(microtime()),rand(0,26),5)
Это слабый код. Там 16 вариантов символов (0-9, a-f) и всего 5 символов. Это дает нам 16^5 = 1 млн вариантов. Мало того, что такой код реально подобрать, может произойти коллизия, то есть 2 студента получат одинаковый код. Я думаю, нам нужен более надежный код, минимум 16-20 символов.
Также, твой код использует ненадежный источник. Текущее время можно примерно угадать и может быть подобрать этот код (хотя так как возможных кодов всего миллион, проще перебирать их). Нельзя использовать время как замену случайному числу. Надо использовать не md5, а просто сгенерировать N случайных символов с помощью mt_rand. Нет ничего более непредсказуемого, чем просто случайные символы. Если ты делаешь преобразования, то ты скорее всего уменьшаешь число возможных вариантов кода и повышаешь предсказуемость.
> https://github.com/V3N0m21/StudentList/blob/master/index.php#L21
> $current = $_GET['current'];
Тут хорошо бы поставить intval, чтобы проходили только числа.
> https://github.com/V3N0m21/StudentList/blob/master/index.php#L26
> $students = $data->searchStudents($search);
Хорошо бы чтобы при поиске работали постраничное отображение и сортировка
> [А-Яа-яЁё]{2,}
Имена/фамилии могут содержать пробелы, дефисы, апостроф: О'Генри, Сан Антуан Кристоф, Римский-Корсаков. Есть фамилии из одной буквы, например китайская фамилия «Ю».
Для всех вводимых в форму человеком данных надо делать trim() так как если случайно ввести пробел, твой скрипт выведет ошибку, а глазами этот пробел не увидеть.
> "/[0-9a-z_]+@[0-9a-z_^\.]+\.[a-z]{2,3}/i",
Почитай статьи:
http://habrahabr.ru/post/224623/
http://habrahabr.ru/post/175375/
http://habrahabr.ru/post/55820/
http://habrahabr.ru/post/123845/#comment_4068527
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L6
Пустой конструктор стоит удалить.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L40
> if(isset($_GET['current'])){
Это не задача пагинатора разбирать GET. Я предлагаю вместо этого передавать номер страницы снаружи и тем самым отвязать пагинатор от глобального массива GET и сделать его более универслаьным.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L45
Весь HTML код и вывод должен быть в шаблонах
> $this->currentItem = 0;
> $this->currentPage = 1;
> $this->start = 0;
> $this->end = 10;
Некоторые из этих свойств лишние так как их можно вывести через другие (напрмиер номера start/end получаются из currentPage и itemsPerPage). Удали избыточные свойства (вместо них можно сделать вычисляющие их методы). Оставь только те свойства которые нельзя вывести.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L11
Неправильно выводить ошибки через die. Во-первых, пользователю они не понятны, во-вторых, ты о них не узнаешь так как они не пишутся в логи. Надо выбрасывать исключение (ловить не обязательно, но если ты хочешь выводить страницу-заглушку вместо белого экрана то можешь сделать ее через set_exception_handler), вот урок: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Кстати, PDO умеет выбрасывать исключения сам. И еще он умеет использовать именованные плейсхолдеры (не только в виде вопросика, но и такие :name)
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L12
Это надо писать в столбик:
$stmt->bind_param(
'sssssssss',
$student->name,
$student->surname,
...
Стандарт: http://www.php-fig.org/psr/psr-2/ru/ (пункт 4.4 Аргументы методов)
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L33
> "SELECT FROM Students WHERE Email='$email'";
Не вставляй данные напрямую, используй плейсхолдеры.
> } else {return "Email is not unique";}
Это не задача маппера генерировать сообщения об ошибках, это задача валидатора. Маппер только должен вернуть «да» иди «нет», уникален такой email или нет.
> $sql = "SELECT FROM Students ORDER BY Mark";
> $sql = $this->db->real_escape_string($sql);
Неправильно. Функция real_escape_string используется для экранирования кавычек и бекслешей (она заменяет их так: ' -> \', " -> \", \ -> \\) при подстановке значений в запрос вручную. Ее применяют к подставляемым данным. Но лучше подставлять данные через плейсхолдеры. У тебя она ничего не делает и не нужна.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L81
> switch ($sort) :
Тут надо использовать версию с фигурными скобками, версия с двоеточием для шаблонов.
break и case принято писать на отдельной строке (case можно писать на одной строке с командой если она одна, но у тебя их тут две).
> https://github.com/V3N0m21/StudentList/blob/master/lib/config.php
Что за сокращения? Всегда называй файлы, классы, функции, переменные нормально, чтобы тому, кто читает код, было легко его понять. Вот тебе статья на эту тему: http://learn.javascript.ru/write-unmain-code
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L4
> include $class . '.php';
Надо проверять есть ли такой файл и только если есть, инклудить (точнее лучше requrie так как он завершает скрипт при ошибке). А твой код выдаст ошибку при попытке сделать например if (class_exists('abababa')) так как эта конструкция вызывает автозагрузчик который попытается подключить несуществующий файл.
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L10
> $path = $_SERVER['DOCUMENT_ROOT'];
Лучше использовать dirname( _ _ DIR _ _ ) так как тогда мы не зависим от настроек Апача.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L47
> $data = $result->fetch_array(MYSQLI_ASSOC);
Если токен доступа неправильный и в базе ничего не найдется то в $data будет null или false и дальше произойдет ошибка. Надо в этом случае наверно возвращать не студента, а null.
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L7
В HTML коде & записывается как & так как это спецсимвол: https://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%B5%D0%BC%D0%BE%D0%BD%D0%B8%D0%BA%D0%B8_%D0%B2_HTML
Гитхаб их красным подсвечивает.
Аналогично символы < и >.
> <?php if($sort =='name' && $dir =='desc') echo '&dir=asc'; ?>
Удобнее наверно писать через тернарный оператор:
<?= ($sort =='name' && $dir =='desc') ? '...' : '...' ?>
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L17
> <?php for ($i = 0; $i < 10; $i++ ) : ?>
Тут лучше использовать foreach
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L9
> <input type="radio" name="Local" value="L" checked> Местный
У тебя не отображается выбранное значение этой опции.
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L12
> <?php if (!isset($_COOKIE['user'])) : ?>
Шаблон не должен лезть в куки/GET/POST, а использовать те переменные что ему дали.
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L2
при выводе данных из переменных в шаблоне надо использовать htmlspecialchars иначе можно сломать верстку (если в данных будут теги) или получить уязвимость XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
Также, у тебя тут есть XSRF: https://github.com/codedokode/pasta/blob/master/security/xsrf.md
Злоумышленник, заманив студента на свою страницу может отправить форму редактирования/регистрации из его браузера на твой сайт. Надо сделать куку с токеном, добавлять этот же токен в форму и сверять перед сохранением в базу. Проверку токена не стоит помещать в валидатор, лучше отдельной функцией.
В общем, давай, исправляй все это и тогда мы перейдем к проверке того все ли у тебя верно работает и выводится.
> [А-Яа-яЁё]{2,}
Имена/фамилии могут содержать пробелы, дефисы, апостроф: О'Генри, Сан Антуан Кристоф, Римский-Корсаков. Есть фамилии из одной буквы, например китайская фамилия «Ю».
Для всех вводимых в форму человеком данных надо делать trim() так как если случайно ввести пробел, твой скрипт выведет ошибку, а глазами этот пробел не увидеть.
> "/[0-9a-z_]+@[0-9a-z_^\.]+\.[a-z]{2,3}/i",
Почитай статьи:
http://habrahabr.ru/post/224623/
http://habrahabr.ru/post/175375/
http://habrahabr.ru/post/55820/
http://habrahabr.ru/post/123845/#comment_4068527
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L6
Пустой конструктор стоит удалить.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L40
> if(isset($_GET['current'])){
Это не задача пагинатора разбирать GET. Я предлагаю вместо этого передавать номер страницы снаружи и тем самым отвязать пагинатор от глобального массива GET и сделать его более универслаьным.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L45
Весь HTML код и вывод должен быть в шаблонах
> $this->currentItem = 0;
> $this->currentPage = 1;
> $this->start = 0;
> $this->end = 10;
Некоторые из этих свойств лишние так как их можно вывести через другие (напрмиер номера start/end получаются из currentPage и itemsPerPage). Удали избыточные свойства (вместо них можно сделать вычисляющие их методы). Оставь только те свойства которые нельзя вывести.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L11
Неправильно выводить ошибки через die. Во-первых, пользователю они не понятны, во-вторых, ты о них не узнаешь так как они не пишутся в логи. Надо выбрасывать исключение (ловить не обязательно, но если ты хочешь выводить страницу-заглушку вместо белого экрана то можешь сделать ее через set_exception_handler), вот урок: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Кстати, PDO умеет выбрасывать исключения сам. И еще он умеет использовать именованные плейсхолдеры (не только в виде вопросика, но и такие :name)
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L12
Это надо писать в столбик:
$stmt->bind_param(
'sssssssss',
$student->name,
$student->surname,
...
Стандарт: http://www.php-fig.org/psr/psr-2/ru/ (пункт 4.4 Аргументы методов)
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L33
> "SELECT FROM Students WHERE Email='$email'";
Не вставляй данные напрямую, используй плейсхолдеры.
> } else {return "Email is not unique";}
Это не задача маппера генерировать сообщения об ошибках, это задача валидатора. Маппер только должен вернуть «да» иди «нет», уникален такой email или нет.
> $sql = "SELECT FROM Students ORDER BY Mark";
> $sql = $this->db->real_escape_string($sql);
Неправильно. Функция real_escape_string используется для экранирования кавычек и бекслешей (она заменяет их так: ' -> \', " -> \", \ -> \\) при подстановке значений в запрос вручную. Ее применяют к подставляемым данным. Но лучше подставлять данные через плейсхолдеры. У тебя она ничего не делает и не нужна.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L81
> switch ($sort) :
Тут надо использовать версию с фигурными скобками, версия с двоеточием для шаблонов.
break и case принято писать на отдельной строке (case можно писать на одной строке с командой если она одна, но у тебя их тут две).
> https://github.com/V3N0m21/StudentList/blob/master/lib/config.php
Что за сокращения? Всегда называй файлы, классы, функции, переменные нормально, чтобы тому, кто читает код, было легко его понять. Вот тебе статья на эту тему: http://learn.javascript.ru/write-unmain-code
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L4
> include $class . '.php';
Надо проверять есть ли такой файл и только если есть, инклудить (точнее лучше requrie так как он завершает скрипт при ошибке). А твой код выдаст ошибку при попытке сделать например if (class_exists('abababa')) так как эта конструкция вызывает автозагрузчик который попытается подключить несуществующий файл.
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L10
> $path = $_SERVER['DOCUMENT_ROOT'];
Лучше использовать dirname( _ _ DIR _ _ ) так как тогда мы не зависим от настроек Апача.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L47
> $data = $result->fetch_array(MYSQLI_ASSOC);
Если токен доступа неправильный и в базе ничего не найдется то в $data будет null или false и дальше произойдет ошибка. Надо в этом случае наверно возвращать не студента, а null.
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L7
В HTML коде & записывается как & так как это спецсимвол: https://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%B5%D0%BC%D0%BE%D0%BD%D0%B8%D0%BA%D0%B8_%D0%B2_HTML
Гитхаб их красным подсвечивает.
Аналогично символы < и >.
> <?php if($sort =='name' && $dir =='desc') echo '&dir=asc'; ?>
Удобнее наверно писать через тернарный оператор:
<?= ($sort =='name' && $dir =='desc') ? '...' : '...' ?>
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L17
> <?php for ($i = 0; $i < 10; $i++ ) : ?>
Тут лучше использовать foreach
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L9
> <input type="radio" name="Local" value="L" checked> Местный
У тебя не отображается выбранное значение этой опции.
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L12
> <?php if (!isset($_COOKIE['user'])) : ?>
Шаблон не должен лезть в куки/GET/POST, а использовать те переменные что ему дали.
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L2
при выводе данных из переменных в шаблоне надо использовать htmlspecialchars иначе можно сломать верстку (если в данных будут теги) или получить уязвимость XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
Также, у тебя тут есть XSRF: https://github.com/codedokode/pasta/blob/master/security/xsrf.md
Злоумышленник, заманив студента на свою страницу может отправить форму редактирования/регистрации из его браузера на твой сайт. Надо сделать куку с токеном, добавлять этот же токен в форму и сверять перед сохранением в базу. Проверку токена не стоит помещать в валидатор, лучше отдельной функцией.
В общем, давай, исправляй все это и тогда мы перейдем к проверке того все ли у тебя верно работает и выводится.
> что при каждой обработке гет-запроса он снова энкодится, как то можно остановить это?
Не вызываеть urlencode если ты используешь http_build_query так как она сама ее вызывает.
>>493479
Сервер перезапустил? Чтобы настройки применились, надо перезапустить Апач.
>>493521
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L11
> EGrid.prototype.addHouse = function() {
Я бы советовал не встраивать в EGrid фабрику других объектов, лучше по моему просто сделать универсальный метод addElement(element). Ну а фабрику производящую дома и электростанции сделать в отдельной функции а не в EGrid. Это не ее задача, создавать объекты.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L65
> arr = this;
Лучше добавлять через push чтобы в нумерации не было дырок.
> //линия с отрицательной мощностью купит энергию. Остальные нас не интересуют
> if ( this.getPower() < 0 ) {
Если бы ты написал
if (this.canBuyPower()) или if (this.getBuyAmount() > 0)
комментарий бы не потребовался.
Код методов sellPower и buyPower очень похож, я думаю ты его копипастил. Избавься от копипасты, сделав одну функцию с флагом, определяющим тип операции. А старые функции sellPower/buyPower пусть вызывают эту универсальную функцию. Назвать можно например tradeEnergy()
> arr.sort(sortBigPrice);
Лучше наверно тут же вписать анонимную функцию сортировки.
> for (var key in arr) {
С массивами лучше работать через for (i = 0; ... или array.forEach() , а for .. in это для словарей (хешей).
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L72
Тут много раз повторяется arr[key], это плохо, надо сделать переменную с понятным названием.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L79
Ветки if и else похожи и их можно объединить, используя Math.max/min
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L129
> this.setPower(power);
Лучше вызвать родительский конструктор явно:
ElementGrid.call(this, power);
Тогда если дописать код в конструктор ElementGrid, он будет выполняться и в потомках.
Кстати, ты наверно заметил что реализация наследования в JS довольно костыльная. Разработчики JS думали что никому не нужны классы и традиционный ООП, а все будут наследовать объекты от объектов (при этом Object.create в первых версиях JS тоже забыли сделать). на практике оказалось наоборот, и есть много библиотек которые упрощают создание классов. Но ты как начинающий должен пока научиться писать их вручную.
В ES6 будет слово class и синтаксис для классов: http://habrahabr.ru/post/241275/
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L136
> this._power = power;
В качестве упражнения было бы полезно вместо этого вызвать метод предка ElementGrid.setPower
> if (timeOfDay == 'day'){
для таких вещей стоит исплоьзовать константы:
var TIME_DAY = 'day';
var TIME_NIGHT = 'night';
или
EGrid.TIME_DAY = 'day';
(это конечно не настоящие константы, а переменные, в ES6 привезут настоящие)
> что при каждой обработке гет-запроса он снова энкодится, как то можно остановить это?
Не вызываеть urlencode если ты используешь http_build_query так как она сама ее вызывает.
>>493479
Сервер перезапустил? Чтобы настройки применились, надо перезапустить Апач.
>>493521
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L11
> EGrid.prototype.addHouse = function() {
Я бы советовал не встраивать в EGrid фабрику других объектов, лучше по моему просто сделать универсальный метод addElement(element). Ну а фабрику производящую дома и электростанции сделать в отдельной функции а не в EGrid. Это не ее задача, создавать объекты.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L65
> arr = this;
Лучше добавлять через push чтобы в нумерации не было дырок.
> //линия с отрицательной мощностью купит энергию. Остальные нас не интересуют
> if ( this.getPower() < 0 ) {
Если бы ты написал
if (this.canBuyPower()) или if (this.getBuyAmount() > 0)
комментарий бы не потребовался.
Код методов sellPower и buyPower очень похож, я думаю ты его копипастил. Избавься от копипасты, сделав одну функцию с флагом, определяющим тип операции. А старые функции sellPower/buyPower пусть вызывают эту универсальную функцию. Назвать можно например tradeEnergy()
> arr.sort(sortBigPrice);
Лучше наверно тут же вписать анонимную функцию сортировки.
> for (var key in arr) {
С массивами лучше работать через for (i = 0; ... или array.forEach() , а for .. in это для словарей (хешей).
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L72
Тут много раз повторяется arr[key], это плохо, надо сделать переменную с понятным названием.
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L79
Ветки if и else похожи и их можно объединить, используя Math.max/min
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L129
> this.setPower(power);
Лучше вызвать родительский конструктор явно:
ElementGrid.call(this, power);
Тогда если дописать код в конструктор ElementGrid, он будет выполняться и в потомках.
Кстати, ты наверно заметил что реализация наследования в JS довольно костыльная. Разработчики JS думали что никому не нужны классы и традиционный ООП, а все будут наследовать объекты от объектов (при этом Object.create в первых версиях JS тоже забыли сделать). на практике оказалось наоборот, и есть много библиотек которые упрощают создание классов. Но ты как начинающий должен пока научиться писать их вручную.
В ES6 будет слово class и синтаксис для классов: http://habrahabr.ru/post/241275/
> https://github.com/tokotun/JS/blob/master/lesson_13.js#L136
> this._power = power;
В качестве упражнения было бы полезно вместо этого вызвать метод предка ElementGrid.setPower
> if (timeOfDay == 'day'){
для таких вещей стоит исплоьзовать константы:
var TIME_DAY = 'day';
var TIME_NIGHT = 'night';
или
EGrid.TIME_DAY = 'day';
(это конечно не настоящие константы, а переменные, в ES6 привезут настоящие)
вакаба скушала все скобки [ i ] в посте выше
>>493542
Я не знаю, как в фаерфоксе, а в Хроме в отладчике (Ctrl + Shift + I) на вкладке Resources можно просматривать содержимое localStorage и по моему даже удалять элементы. Это может тебе пригодиться.
Чтобы понять почему не работает проверка, попробуй отладчиком поставить точку останова в функции и пройти ее по шагам, наблюдая чему равны переменные. Как использовать отладчик описано тут: http://learn.javascript.ru/debugging-chrome
Ты также можешь во время паузы писать команыд в консоли и например смотреть что в localStorage или что вернет функция.
Отлаживать удобнее будет на отдельной странице просмотра результат: https://jsfiddle.net/d4a05n5w/8/embedded/result/ а не в редакторе jsfiddle.
Я думаю, эта проверка
> if (localStorage.getItem(a.name) == a.name) {
Неправильная так акк getItem вернет не имя, а JSON. Тебе просто надо проверять что результат не равен null.
> console.log((JSON.parse(localStorage.getItem(article_3.name))).name);
> //После того, как интерпретатор видит, что такого объекта нет в локальном хранилище, он прерывает работу(?)
Не совсем. Тебе стоило бы писать это не в одну строку, а в несколько чтобы было понятнее:
var name = article_3.name;
var json = localStorage.getItem(name); // получается null так как элемента нет в хранилище
var item = JSON.parse(json); // получается тоже null
var result = item.name; // попытка обратиться к полю name у не-объекта, выбрасывается исключение и выполнение программы прерывается
То есть не пиши много команд в одну строчку, тебе же будет проще разбираться.
> //Цикл прохода по локальному хранилищу
> for (i=0; i<4; i++) {
Зачем ты сделал цикл? Достаточно же сделать одну проверку: есть элемент с таким названием в хранилище или нет? А ты 4 раза проверяешь одно и то же.
вакаба скушала все скобки [ i ] в посте выше
>>493542
Я не знаю, как в фаерфоксе, а в Хроме в отладчике (Ctrl + Shift + I) на вкладке Resources можно просматривать содержимое localStorage и по моему даже удалять элементы. Это может тебе пригодиться.
Чтобы понять почему не работает проверка, попробуй отладчиком поставить точку останова в функции и пройти ее по шагам, наблюдая чему равны переменные. Как использовать отладчик описано тут: http://learn.javascript.ru/debugging-chrome
Ты также можешь во время паузы писать команыд в консоли и например смотреть что в localStorage или что вернет функция.
Отлаживать удобнее будет на отдельной странице просмотра результат: https://jsfiddle.net/d4a05n5w/8/embedded/result/ а не в редакторе jsfiddle.
Я думаю, эта проверка
> if (localStorage.getItem(a.name) == a.name) {
Неправильная так акк getItem вернет не имя, а JSON. Тебе просто надо проверять что результат не равен null.
> console.log((JSON.parse(localStorage.getItem(article_3.name))).name);
> //После того, как интерпретатор видит, что такого объекта нет в локальном хранилище, он прерывает работу(?)
Не совсем. Тебе стоило бы писать это не в одну строку, а в несколько чтобы было понятнее:
var name = article_3.name;
var json = localStorage.getItem(name); // получается null так как элемента нет в хранилище
var item = JSON.parse(json); // получается тоже null
var result = item.name; // попытка обратиться к полю name у не-объекта, выбрасывается исключение и выполнение программы прерывается
То есть не пиши много команд в одну строчку, тебе же будет проще разбираться.
> //Цикл прохода по локальному хранилищу
> for (i=0; i<4; i++) {
Зачем ты сделал цикл? Достаточно же сделать одну проверку: есть элемент с таким названием в хранилище или нет? А ты 4 раза проверяешь одно и то же.
А, и еще. Твой код не показывает содержимое корзины — это хорошо? Было бы наверно лучше если бы там в углу страницы выводился список товаров в корзине (и была кнопочка удалить).
Насчет JS, если ты не очень хорошо его знаешь, не хочешь порешать наши задачки на JS из Оп-поста? Они помогут тебе испраить пробелы в знаниях.
Ну и в наши дни крутые фронтендщики делают такие штуки на библиотеках вроде Knockout, Angular, но, прежде чем за них браться, надо освоить чистый JS в совершенстве.
> Как правильно делать обход по лок. хранилищу?
Тут написано что у хранилища есть свойство length и функция key() возвращающая ключ который хранится под указанным номером. Соответственно ты можешь обойти все номера от 0 до length - 1 и получить все ключи в хранилище. Но я не советую так делать. Ведь кроме твоей корзины, там могут быть другие данные от других скриптов — как ты их будешь различать?
Я советую поменять схему хранения. например вместо того чтобы каждому товару делать свой ключ, сделать один элемент: массив всех добавленных товаров, и хранить только один этот массив в едиснтвенном ключе. Тогда чтобы получить список товаров в корзине не требуется обходить все хранилище, достаточно взять один этот ключ.
Ты кладешь аргументы не в том порядке. Сначала идут переданные в partial аргументы, а потом переданные в внутреннюю функцию. У тебя наоборот.
А partialAny ты прошел наверно из-за того что там другая функция с другим алгоритмом.
Также, еще советы:
> var fn = arguments[0];
лучше явно сделать аргумент fn у функции: function partial(fn) { ....
> for (var i = 1; i < arguments.length; i++) {
> args.push(arguments);
Вместо цикла можно исплоьзовать Array.prototype.slice: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/slice#Array-like
Сделай-ка через slice, это часто используется.
> Как мне нормально реализовать автозагрузку?
для начала научись делать автозагрузку через spl_autoload_register, когда научишься, сотри ее и сделай через composer.json.
Ссылки:
http://habrahabr.ru/post/136761/
http://habrahabr.ru/post/138920/
Твой автозагрузчик может выглядеть примерно так:
spl_autoload_register function {
файл = получить имя файла из имени класса;
если (файл существует) {
зареквайрить его;
}
}
composer умеет делать автозагрузку сам, достаточно дописать пару опций в composer.json и сделать composer dump-autoload:
https://getcomposer.org/doc/04-schema.md#autoload (англ)
http://zenwalker.me/blog/php-psr-0-vs-psr-4.html
http://onedev.net/post/176
Чтобы это работало тебе придется назвать свои классы в соовтетсвии со стандартом PSR 4: http://www.php-fig.org/psr/psr-4/ru/meta/
Если кратко то мы используем неймспейсы которые совпадают с именами папок в которых лежит файл.
В композере достаточно прописать что-то вроде
....
"psr-4": {"": "src/"}
и автозагрузка заработает (после того как сделашеь dump-autoload конечно).
> Как мне нормально реализовать автозагрузку?
для начала научись делать автозагрузку через spl_autoload_register, когда научишься, сотри ее и сделай через composer.json.
Ссылки:
http://habrahabr.ru/post/136761/
http://habrahabr.ru/post/138920/
Твой автозагрузчик может выглядеть примерно так:
spl_autoload_register function {
файл = получить имя файла из имени класса;
если (файл существует) {
зареквайрить его;
}
}
composer умеет делать автозагрузку сам, достаточно дописать пару опций в composer.json и сделать composer dump-autoload:
https://getcomposer.org/doc/04-schema.md#autoload (англ)
http://zenwalker.me/blog/php-psr-0-vs-psr-4.html
http://onedev.net/post/176
Чтобы это работало тебе придется назвать свои классы в соовтетсвии со стандартом PSR 4: http://www.php-fig.org/psr/psr-4/ru/meta/
Если кратко то мы используем неймспейсы которые совпадают с именами папок в которых лежит файл.
В композере достаточно прописать что-то вроде
....
"psr-4": {"": "src/"}
и автозагрузка заработает (после того как сделашеь dump-autoload конечно).
> Есть модель, в ней case do-new-entry
Это контроллер наверно?
Из твоего вопроса не очень понятно, в чем именно проблема? Как это организовать? Лучше всего так:
— сделать отдельный класс (или функции), для работы с базой, получения данных, вставки данных
— если используешь ООП то сделать еще класс Post хранящий информаию об одном посте. Если не используешь ООП, придется передавать массивы, и это плохо.
— в контроллере создаешь объект post(или массив что хуже) и передаешь в функцию сохранения
Вот у меня урок про работу с базой с использованием ООП: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
Вот урое про работу с формами: https://github.com/codedokode/pasta/blob/master/forms.md
Вот простая (хотя на мой взгляд довольно неточная) статья про MVC: http://habrahabr.ru/post/150267/
>>494019
Это решается написанием соответствующего CSS кода, JS тут наверно не требуется. Но я вижу из твоего вопроса что ты видимо не очень хорошо знаешь CSS, если так то тебе лучше изучить его как следует, чтобы в дальнейшем не стопориться на таких проблемах. У нас есть в ОП-посте задания на HTML/CSS которые помогут тебе в них разобраться.
> Надо что то прописать в ксс стилях, какой-то отступ?
зависит от того как у тебя сверстано. Скорее всего там абсолютное позиионирование и надо правильно выставлять top/left/right/bottom/margin
У тебя в таблицу user_like можно вставить 2 раза один и тот же лайк. Надо добавить уникальный индекс, а лучше первичный ключ (который уникален по определению) на обе колонки чтобы этого не было.
> id INT,
> to_user INT,
У обязательных к заполнению полей надо ставить NOT NULL
> COUNT(DISTINCT t1.to_user) as given_likes,
> COUNT(DISTINCT t2.id) as received_likes
Это выглядит правдоподобно, считать число различных id кому потавлен/от кого получен лайк
> COUNT(t1.id) as given_likes,
> COUNT(t1.to_user) as received_likes,
> COUNT(DISTINCT t2.id) as mutual_likes
А вот это по моему как-то запутанно. У тебя число полуенных лайков и отданных одинаковое выводится (забыл distinct?)
Посмотри еще раз на таблицу без группировки (можешь ее вывести для своих данных):
юзер | кому поставил | от кого получил
юзер1 | 2 | 3
юзер1 | 2 | 6
юзер1 | 3 | 3
юзер1 | 3 | 6
юзер1 | 4 | 3
юзер1 | 4 | 6
Ты видишь здесь взаимный лайк? Он тут один.
Тебе надо написать выражение которое вернет 1 для взаимного лайка и 0 для остальных. Затем при группировке просуммировать это выражение по всем сгруппированным строчкам и ты получишь число взаимных лайков у пользователя.
У тебя в таблицу user_like можно вставить 2 раза один и тот же лайк. Надо добавить уникальный индекс, а лучше первичный ключ (который уникален по определению) на обе колонки чтобы этого не было.
> id INT,
> to_user INT,
У обязательных к заполнению полей надо ставить NOT NULL
> COUNT(DISTINCT t1.to_user) as given_likes,
> COUNT(DISTINCT t2.id) as received_likes
Это выглядит правдоподобно, считать число различных id кому потавлен/от кого получен лайк
> COUNT(t1.id) as given_likes,
> COUNT(t1.to_user) as received_likes,
> COUNT(DISTINCT t2.id) as mutual_likes
А вот это по моему как-то запутанно. У тебя число полуенных лайков и отданных одинаковое выводится (забыл distinct?)
Посмотри еще раз на таблицу без группировки (можешь ее вывести для своих данных):
юзер | кому поставил | от кого получил
юзер1 | 2 | 3
юзер1 | 2 | 6
юзер1 | 3 | 3
юзер1 | 3 | 6
юзер1 | 4 | 3
юзер1 | 4 | 6
Ты видишь здесь взаимный лайк? Он тут один.
Тебе надо написать выражение которое вернет 1 для взаимного лайка и 0 для остальных. Затем при группировке просуммировать это выражение по всем сгруппированным строчкам и ты получишь число взаимных лайков у пользователя.
Эти выражения
COUNT(t1.id) as given_likes,
COUNT(t1.to_user) as received_likes,
Всегда дадут одинаковый ответ так как они считают число не равных NULL строчек в таблице t1
> если (кому поставил = от кого получил, то вернуть единицу, иначе NULL).
Лучше не NULL а 0, а то суммировать нельзя будет.
>>494122
count там не нужен. Просто в внутренней функции запоминай текущее значение счетчика (чтобы вернуть) и увеличивай счетчик на шаг.
Алсо
> return a+step;
Ты не увеличиваешь a и второй, третий, четвертый ... разы она вернет одно и то же, попробуй сам вызывать.
https://github.com/Integer64/myTestSite.dev/tree/master/vecktor_OOP
ОП передала и сделал все 3 варианта.
Нужно твое авторитетное мнение.
http://ideone.com/cuf7PU
Почитай про приведение типов
http://php.net/manual/ru/language.types.type-juggling.php
По твоему примеру PHP пытается привести строку к числу, и делает из "2.5sdfsgr" просто 2.5
если тебе надо более точное сравние используй === тогда сравнивается типы примитивов и объекты.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Department.php#L17
> $this->employees->offsetSet($employee);
Вообще, для добавления объекта там есть метод attach() (а для удаления detach()). Он делает по сути то же.
Кстати, offsetSet это магический метод: http://php.net/manual/ru/class.arrayaccess.php
Он вызывается когда ты пишешь
$x[$y] = $z;
$x[]= $y;
Ты можешь использовать ArrayAccess если захочешь чтобы к твоему объекту можно было обращаться как к массиву через скобки.
> $employees = $this->getEmployees();
> if($employees->offsetExists($employee)){
> $employees->offsetUnset($employee);
> $this->employees = $employees;
Вот это сложно как-то. Ты зачем-то ссылку на SplObjectStotrage копируешь в переменную, а затем назад в $this->employees. Но ты не учел того, что объекты копируются и передаются как по ссылке:
$a = new MyClass();
$b = $a; // $b и $a указывают на один объект
$a->x = 100;
echo $b->x; // тоже 100
Мануал: http://php.net/manual/ru/language.oop5.references.php
Таким образом манипуляция с переменными не имеет смысла, тебе лучше сразу писать $this->employees->detach(...);
Ну и вызов offsetUnset это магический метод который вызовется при
unset($employees[$employee])
Но так как у SplObjectStorage есть detach, то удобнее вызвать его.
Откуда я вижу что эти методы магические? Из описания интерфейсов в мануале:
SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess {
По ссылкам можно увидеть что это за интерфейсы и для чего они нужны. Countable например позволяет переопределить поведение count($x) на твоем объекте, Iterator переопределяет поведение foreach, Serializable поведение serialize().
> return round($wageCosts, 2);
Округлять надо при выводе, а возвращать лучше точные значения.
> public function setEmployees($employees)
Тут нет type hint и я думаю, этот метод вообще не нужен. Достаточно методов add/delete (и clear если хочется уволить всех разом)
Теперь по поводу класса Employee. Давай сделаем тест, что будет если несколько раз поменять ранг сотрудника (зарплата в итоге должна остаться та же):
http://ideone.com/fTtJLf
Как видишь, твой объект начинает выдавать неточные данные.
> class VecktorVersion1 extends Vecktor{
Я думаю тут вместо наследования логичнее сделать отдельный класс или функцию, который берет объект-компанию, меняет в ней что надо и выводит статистику повторно.
Также, надо бы чтобы было скрипт, мы его запускали и видели 4 таблички (исходная + 3 варианта)
Может быть тебе понадобится как-то клонировать компанию с департаментами и работниками, чтобы каждый антикризисный сценарий работал со своей копией.
> if(is_a($employee, 'Engineer')){
Это по моему старая функция, сейчас используют оператор instanceof
> // Пока нужно количество работников не уволено
> while($countToFire > 0)
Ты можешь просто отобрать кандидатов на увольнение с помощью array_slice и уволить через foreach. Общий порядок такой:
— отбираем всех кто подпадает под увольнение
— сортируем так, чтобы сначала шли инженеры первого ранга, потом второго
— считаем сколько будет 50%
— отбираем увольняемых через array_slice
— увольняем через foreach
Это будет гораздо проще. Аналогично с повышением 50% менеджеров.
> // Делаем сериализацию в строку
> $storageString = $employees->serialize();
> // Проверем есть ли в департаменте Аналитики
> if(strpos($storageString, 'Analyst') !== false) {
Это жуткие костыли. А что если там например есть объект класса MarketAnalyst (который добавили позже) или у человека имя такое? К тому же формат сериализации не описан и может в любое время меняться. Так делать конечно нельзя.
> if ($employee->getBoss() === true
Операция === возвращает true или false и потому можно просто писать
if ($employee->getBoss()) { ...
> // Если этот аналитик круче нашего шаблона
> if ($employee->getRank() > $greatestAnalyst->getRank()) {
> // Понижаем старого крутого аналитика
> $greatestAnalyst->setBoss(false);
Тут по моему как-то все сложно. Тут просто надо найти самого крутого аналитика отдельным циклом например и босса и сравнить их ранги, если они разные, то переставить местами.
Разумеется это лучше сделать отдельными функциями.
> // Запускаем процесс увелечения ЗП и кофе
> $this->upgradeManager($employees, $department);
По моему в метод достаточно передать только департамент, employee он сам может получить.
> $engineer->setRank(++$rank);
лучше писать $rank + 1
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Department.php#L17
> $this->employees->offsetSet($employee);
Вообще, для добавления объекта там есть метод attach() (а для удаления detach()). Он делает по сути то же.
Кстати, offsetSet это магический метод: http://php.net/manual/ru/class.arrayaccess.php
Он вызывается когда ты пишешь
$x[$y] = $z;
$x[]= $y;
Ты можешь использовать ArrayAccess если захочешь чтобы к твоему объекту можно было обращаться как к массиву через скобки.
> $employees = $this->getEmployees();
> if($employees->offsetExists($employee)){
> $employees->offsetUnset($employee);
> $this->employees = $employees;
Вот это сложно как-то. Ты зачем-то ссылку на SplObjectStotrage копируешь в переменную, а затем назад в $this->employees. Но ты не учел того, что объекты копируются и передаются как по ссылке:
$a = new MyClass();
$b = $a; // $b и $a указывают на один объект
$a->x = 100;
echo $b->x; // тоже 100
Мануал: http://php.net/manual/ru/language.oop5.references.php
Таким образом манипуляция с переменными не имеет смысла, тебе лучше сразу писать $this->employees->detach(...);
Ну и вызов offsetUnset это магический метод который вызовется при
unset($employees[$employee])
Но так как у SplObjectStorage есть detach, то удобнее вызвать его.
Откуда я вижу что эти методы магические? Из описания интерфейсов в мануале:
SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess {
По ссылкам можно увидеть что это за интерфейсы и для чего они нужны. Countable например позволяет переопределить поведение count($x) на твоем объекте, Iterator переопределяет поведение foreach, Serializable поведение serialize().
> return round($wageCosts, 2);
Округлять надо при выводе, а возвращать лучше точные значения.
> public function setEmployees($employees)
Тут нет type hint и я думаю, этот метод вообще не нужен. Достаточно методов add/delete (и clear если хочется уволить всех разом)
Теперь по поводу класса Employee. Давай сделаем тест, что будет если несколько раз поменять ранг сотрудника (зарплата в итоге должна остаться та же):
http://ideone.com/fTtJLf
Как видишь, твой объект начинает выдавать неточные данные.
> class VecktorVersion1 extends Vecktor{
Я думаю тут вместо наследования логичнее сделать отдельный класс или функцию, который берет объект-компанию, меняет в ней что надо и выводит статистику повторно.
Также, надо бы чтобы было скрипт, мы его запускали и видели 4 таблички (исходная + 3 варианта)
Может быть тебе понадобится как-то клонировать компанию с департаментами и работниками, чтобы каждый антикризисный сценарий работал со своей копией.
> if(is_a($employee, 'Engineer')){
Это по моему старая функция, сейчас используют оператор instanceof
> // Пока нужно количество работников не уволено
> while($countToFire > 0)
Ты можешь просто отобрать кандидатов на увольнение с помощью array_slice и уволить через foreach. Общий порядок такой:
— отбираем всех кто подпадает под увольнение
— сортируем так, чтобы сначала шли инженеры первого ранга, потом второго
— считаем сколько будет 50%
— отбираем увольняемых через array_slice
— увольняем через foreach
Это будет гораздо проще. Аналогично с повышением 50% менеджеров.
> // Делаем сериализацию в строку
> $storageString = $employees->serialize();
> // Проверем есть ли в департаменте Аналитики
> if(strpos($storageString, 'Analyst') !== false) {
Это жуткие костыли. А что если там например есть объект класса MarketAnalyst (который добавили позже) или у человека имя такое? К тому же формат сериализации не описан и может в любое время меняться. Так делать конечно нельзя.
> if ($employee->getBoss() === true
Операция === возвращает true или false и потому можно просто писать
if ($employee->getBoss()) { ...
> // Если этот аналитик круче нашего шаблона
> if ($employee->getRank() > $greatestAnalyst->getRank()) {
> // Понижаем старого крутого аналитика
> $greatestAnalyst->setBoss(false);
Тут по моему как-то все сложно. Тут просто надо найти самого крутого аналитика отдельным циклом например и босса и сравнить их ранги, если они разные, то переставить местами.
Разумеется это лучше сделать отдельными функциями.
> // Запускаем процесс увелечения ЗП и кофе
> $this->upgradeManager($employees, $department);
По моему в метод достаточно передать только департамент, employee он сам может получить.
> $engineer->setRank(++$rank);
лучше писать $rank + 1
А это что за класс?
https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/OneSpecimenPerHashStorage.php
Сторадж, из которого потом нельзя ничего извлечь и удалить так как хеш генерируется случайно?
Эт я извращался забыл удалить )
Хочу купить что-то удобное, потому что сейчас люто затекает спина и шея (геморроя как ни странно нет, сам удивляюсь).
Чем нужно руководствоваться при выборе седлушки?
Чем недоволен ололоша?
>>494519
Нагуглил какой-то гост, может кому интересно. Здоровье - важная штука.
http://www.ohranatruda.ru/ot_biblio/normativ/data_normativ/39/39082/
9.6. Конструкция рабочегостула (кресла) должна обеспечивать поддержание рациональной рабочей позы приработе на ПЭВМ, позволять изменять позу с целью снижения статическогонапряжения мышц шейно-плечевой области и спины для предупреждения развитияутомления. Тип рабочего стула (кресла) следует выбирать с учетом ростапользователя, характера и продолжительности работы с ПЭВМ.
Рабочий стул (кресло) долженбыть подъемно-поворотным, регулируемым по высоте и углам наклона сиденья испинки, а также расстоянию спинки от переднего края сиденья, при этомрегулировка каждого параметра должна быть независимой, легко осуществляемой ииметь надежную фиксацию.
9.7. Поверхность сиденья,спинки и других элементов стула (кресла) должна быть полумягкой, снескользящим, слабо электризующимся и воздухопроницаемым покрытием,обеспечивающим легкую очистку от загрязненийлол.
А у тебя монитор на какой высоте относительно глаз? Если монитор слишком высоко то как раз будет болеть шея. Если это твой случай то погугли на какой высоте он должен быть, там глаза должны быть примерно на уровне верхнего края экрана.
Ну то есть я думаю, дело может быть не в модели стула, а в высоте стола/стула/экрана.
Вы, няши, еще даже 650 постов не набили, а уже перекат хотите. Подожди еще немного, скоро перекатимся.
В задаче требуется генерировать превьюшки не при выводе страницы, а только когда браузер обратится к ним. И разумеется генерироваться превьюшка дложна только в первый раз, во второй сразу должна отдаваться с диска.
То есть если условно говоря ссылка на превьюшку имеет вид
http://example.com/preview/50x100/picture.png
То при первом обращении по ссылке должна сгенерироваться превьюшка и создаться файл /preview/50x100/picture.png, а при втором и далее просто отдается этот файл.
Сделать это можно перенастроив Апач через htaccess, например с помощью mod_rewrite, чтобы обращения к несуществующим пока картинкам перенаправлялись на php скрипт.
Вообще, это относительно сложная задача, может стоит сначала со списком студентов разобраться.
Это хорошо, тогда доделывай превьюшки. Кстати, эта штука может пригодиться в задании на файлоообменник чтобы выводить умеьшенные версии картинок.
Что-то я еще больше запутался. Хотя уже почти сделал обычным способом загрузку.
>В задаче требуется генерировать превьюшки не при выводе страницы, а только когда браузер обратится к ним
Ну вот у меня на главной странице что-то вроде галереи. Это же и есть обращение к превьюшкам. А сами картинки это ссылки на оригинал.
Делал в файлообменнике тупой подгон размера стилями, это кое-как оправдано, когда нужно вывести одно изображение на странице.
Но если нужно выстроить галерею из сотен картинок уменьшенного размера, это не подходит.
Киньте ссылку на задание и материалы по теме работы с изображениями в php.
Сделай нормальное оглавление по темам и задачам.
Обращение к превьюшке это когда браузер увидев тег <img> отправляет запрос на получение картинки. Зачем генерировать их пока их никто не запросил?
Идея в том что мы запускаем PHP скрипт и генерируем превьюшку только в первый раз (во второй раз там уже будет файл на диске и Апач отдаст его не запуская PHP). И соответственно когда мы выводим страницу нам нет необходимости вообще что-то проверять и генерировать. И если страницу запрашивает например бот-поисковик (который не скачивает картинки) то ничего не генерируется.
А в твоем варианте при каждой загрузке страницы мы должны обходить все файлы картинок, проверять есть ли для них превьюшки .. .по моему ты переусложняешь все.
> Делал в файлообменнике тупой подгон размера стилями, это кое-как оправдано, когда нужно вывести одно изображение на странице.
нет, не оправдано. Лишний ненужный трафик для сервера и пользователей + браузеры уменьшают картинки не очень качественно + в тяжелых слуаях браузер может начать притормаживать.
> Киньте ссылку на задание
В самом низу страницы http://archive-ipq-co.narod.ru/l1/pasta.html
>>494554
А что ты пробовал искать? На сайте или на гитхабе? На гитхабе я пока не сделал оглавление, да и предполагается что уроки там временно и потом они переедут на сайт.
Пробовал искать это задание на превью картинок, мимопроходил, увидел постановку задачи, заинтересовался.
Ты уж извини, но я на память не помню структуру твоих уроков. А переходить по всем ссылкам и просматривать все статьи не вариант.
И еще просьба от будущих пользователей сайта: пагинацию не просто так придумали, разбивай эти громадные статьи на части. Два-три экрана, не больше.
Спасибо за замечания. Конечно, я не всегда могу предугадать как именно люди будут пользоваться сайтом и такая обратная связь по навигации очень ценна.
Насчет поиска, согласен, не очень понятно как найти это задание. Даже гугл не ищет ничего по словам «превью картинок», но показывает результат если написать «превьюшки» (попробуй догадайся): http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=site%3Aarchive-ipq-co.narod.ru+%D0%BF%D1%80%D0%B5%D0%B2%D1%8C%D1%8E%D1%88%D0%BA%D0%B8
У меня конечно учебник пока что рассчитан только на последовательное чтение.
Из выходов я вижу разве что сделать отдельное оглавление задач (или осилить и написать поиск? но тут мы вернемся к проблеме словоформ превью - превьюшки), но тут надо посмотреть, многим ли оно будет нужно.
> пагинацию не просто так придумали, разбивай эти громадные статьи на части. Два-три экрана, не больше.
Разве повернуть колесо мыши или нажать PageDown не быстрее чем ткнуть ссылку и перейти на другую страницу? Ну и к началу вернуться проще. Просто я сам больше люблю длинные страницы, и мне они кажутся более удобными.
Статьи разбивают на страницы не из заботы о пользователях, а ради того чтобы было больше просмотров страниц и просмотров рекламы.
Вот пример статьи с сайта BBC: http://www.bbc.com/news/magazine-32961309
Вот пример статьи на популярном блоге medium: https://medium.com/@kevinstownsend/two-weeks-ago-i-almost-died-in-the-deadliest-plane-crash-ever-c2f8d68a917c
Как видишь, они не разбиты на части. Потому мне кажется что и уроки разбивать не стоит. Чего не хватает, так это возможности дать ссылку на подраздел, чтобы при открытии страница прокручивалась к нужному месту (например сразу к задаче), это надо будет сделать.
Если меня укусит php-шник, я тоже стану таким?
Я правильно понял, что пространство имен по сути совпадает с путем к файлу класса в файловой системе?
Если у меня в index.php стоит
$model = new models\UserModel;
то я ссылаюсь на файл UserModel.php, который лежит в папке models, которая находится на уровень ниже index.php, то есть ./models/UserModel.php ?
RewriteEngine On
RewriteCond %(HTTP_HOST)%(REQUEST_URI) '!-f'
RewriteRule ^([a-zA-Z0-9\.]+)$ test.php?fname=$1 [NC]
И всегда редиректит на test.php
> https://github.com/V3N0m21/StudentList/blob/master/index.php#L26
> $students = $data->searchStudents($search);
>Хорошо бы чтобы при поиске работали постраничное отображение и сортировка
Подскажи как это сделать, потому что мне ничего в голову не приходит. Это нужно отдельно как-то сохранять то что будет в выдаче, и уже по этому сортировать? Или вообще переделать метод searchStudents так чтоб в него попадал еще выбор сортировки и ее направление? Но тогда я не совсем понимаю как с этим делать пагинацию
Чтобы разобраться в PSR-4 и пространствах имен, надо понять, почему они появились и какую задачу решают.
Пространства имен решают проблему слишком длинных имен классов. Длинные имена появляются по 2 причинам:
— борьба с конфликтом имен. Представь что Вася и Петя каждый пишет свои библиотеки и оба решают использовать класс с одинаковым названием, например User. Или функцию getUser(). Если мы попробуем подключить в проекте обе этих библиотеки, будет ошибка так как не может быть 2 классов с одинаковыми именами. Чтобы этого избежать, библиотеки приписывают к классам и функциям свое название в начало:
Petya_User
petyaGetUser()
Vasya_User
vasyaGetUser()
Zend_Mail
sfController
Если не приписывать в начало имя библиотеки то конфликт обязательно будет так как в мире тысячи библиотек и в каких-нибудь двух обязательно будут совпадающие названия.
— большие библиотеки и фрейморки состоят из вложенных друг в друга модулей и компонент и имена классов получаются длиными:
Zend_Db_Table_Row_Abstract — это класс фреймворка Zend Framework 1, модуль Db.
sfDatabaseConfigHandler — класс фреймворка Symfony1, модуль Database
В общем, до неймспейсов мы имели длинные имена классов. Длинные имена это плохо, так как они увеличивают длину строк и снижают читаемость.
Неймспейсы решают эту проблему тем что вводят возможность помещать класс (и функции) в неймспейсы:
\Symfony\Routing\Router
\Doctrine\ORM\Mapping\Id
\Petya\User
\Vasya\User
При этом ты можешь как и раньше писать длинное имя класса со всеми неймспейсами, а можешь создать синоним через
use \Symfony\Routing\Router;
и писать просто Router.
По умолчанию, если ты не указываешь неймспейс то твои классы создаются в глобальном неймспейсе.
Сам PHP не требует чтобы имя класса совпадало с именем файла, а неймспейсов с именами папок. Ему без разницы где хранится класс. Но когда ты пишешь автозагрузчик, тебе нужны какие-то правила, как узнать по полному имени класса путь к файлу с ним, чтобы подключить. И желательно чтобы правила были общие, чтобы каждый не придумывал свой велосипед.
Эту проблему (как назвать файл с классом) решает PSR-4. Это договоренность, что мы кладем класс с неймспейсом
MyLibrary\A\B\C\D
в файл
my-library/src/A/B/C/D.php
Если ты придерживаешься этого стандарта, то во-первых, ты молодец, во-вторых ты можешь не писать свой автозагрузчик, а взять любой готовый автозагручик PSR-4 (например встроенный в композер). Единственное, что тебе надо указать — это корневой неймспейс твоего проекта и корневую папку.
То есть если ты укажешь корневой неймспейс MyLibrary, а папку my-library/src то автозагрузчик будет искать файлы в неймспейсе MyLIbrary в этой папке.
Давай повторим еще раз:
— длинные имена классов это неизбежность, так как библиотек тысячи, в них бывает много классов и эти имена должны быть уникальными
— PSR-4 это договоренность о том, как называть и куда класть файлы с классами, чтобы их мог найти автозагрузчик и чтобы все использовали готовый автозагрузчик и не изобретали свой.
Что скажешь? Хорошее решение или эти проблемы можно было решить как-то лучше?
Теперь, зная это, я надеюсь ты без труда сможешь привести свой проект к стандарту PSR-4 и настроить автозагрузку классов через встроенный в композер автозагрузчик. И больше никогда не писать автозагрузчики.
Кстати, до PSR-4 был PSR-0. Он ориентирован на старые проекты, где не было неймспейсов, а имена папок разделялись подчеркиваниями, вот так:
Класс Zend_Db_Table_Row_Abstract
Файл Zend/Db/Table/Row/Abstract.php
PSR-0 устарел и я думаю, не стоит к нему возвращаться. Но композер поддерживает и его тоже.
Чтобы разобраться в PSR-4 и пространствах имен, надо понять, почему они появились и какую задачу решают.
Пространства имен решают проблему слишком длинных имен классов. Длинные имена появляются по 2 причинам:
— борьба с конфликтом имен. Представь что Вася и Петя каждый пишет свои библиотеки и оба решают использовать класс с одинаковым названием, например User. Или функцию getUser(). Если мы попробуем подключить в проекте обе этих библиотеки, будет ошибка так как не может быть 2 классов с одинаковыми именами. Чтобы этого избежать, библиотеки приписывают к классам и функциям свое название в начало:
Petya_User
petyaGetUser()
Vasya_User
vasyaGetUser()
Zend_Mail
sfController
Если не приписывать в начало имя библиотеки то конфликт обязательно будет так как в мире тысячи библиотек и в каких-нибудь двух обязательно будут совпадающие названия.
— большие библиотеки и фрейморки состоят из вложенных друг в друга модулей и компонент и имена классов получаются длиными:
Zend_Db_Table_Row_Abstract — это класс фреймворка Zend Framework 1, модуль Db.
sfDatabaseConfigHandler — класс фреймворка Symfony1, модуль Database
В общем, до неймспейсов мы имели длинные имена классов. Длинные имена это плохо, так как они увеличивают длину строк и снижают читаемость.
Неймспейсы решают эту проблему тем что вводят возможность помещать класс (и функции) в неймспейсы:
\Symfony\Routing\Router
\Doctrine\ORM\Mapping\Id
\Petya\User
\Vasya\User
При этом ты можешь как и раньше писать длинное имя класса со всеми неймспейсами, а можешь создать синоним через
use \Symfony\Routing\Router;
и писать просто Router.
По умолчанию, если ты не указываешь неймспейс то твои классы создаются в глобальном неймспейсе.
Сам PHP не требует чтобы имя класса совпадало с именем файла, а неймспейсов с именами папок. Ему без разницы где хранится класс. Но когда ты пишешь автозагрузчик, тебе нужны какие-то правила, как узнать по полному имени класса путь к файлу с ним, чтобы подключить. И желательно чтобы правила были общие, чтобы каждый не придумывал свой велосипед.
Эту проблему (как назвать файл с классом) решает PSR-4. Это договоренность, что мы кладем класс с неймспейсом
MyLibrary\A\B\C\D
в файл
my-library/src/A/B/C/D.php
Если ты придерживаешься этого стандарта, то во-первых, ты молодец, во-вторых ты можешь не писать свой автозагрузчик, а взять любой готовый автозагручик PSR-4 (например встроенный в композер). Единственное, что тебе надо указать — это корневой неймспейс твоего проекта и корневую папку.
То есть если ты укажешь корневой неймспейс MyLibrary, а папку my-library/src то автозагрузчик будет искать файлы в неймспейсе MyLIbrary в этой папке.
Давай повторим еще раз:
— длинные имена классов это неизбежность, так как библиотек тысячи, в них бывает много классов и эти имена должны быть уникальными
— PSR-4 это договоренность о том, как называть и куда класть файлы с классами, чтобы их мог найти автозагрузчик и чтобы все использовали готовый автозагрузчик и не изобретали свой.
Что скажешь? Хорошее решение или эти проблемы можно было решить как-то лучше?
Теперь, зная это, я надеюсь ты без труда сможешь привести свой проект к стандарту PSR-4 и настроить автозагрузку классов через встроенный в композер автозагрузчик. И больше никогда не писать автозагрузчики.
Кстати, до PSR-4 был PSR-0. Он ориентирован на старые проекты, где не было неймспейсов, а имена папок разделялись подчеркиваниями, вот так:
Класс Zend_Db_Table_Row_Abstract
Файл Zend/Db/Table/Row/Abstract.php
PSR-0 устарел и я думаю, не стоит к нему возвращаться. Но композер поддерживает и его тоже.
> Я правильно понял, что пространство имен по сути совпадает с путем к файлу класса в файловой системе?
Нет, оно не обязано совпадать, ты можешь придумывать любые имена неймспейсам. Но чтобы работал автозагрузчик, нужна договоренность о соответствии имени класса и пути к файлу. PSR-4 и есть эта договоренность.
> я ссылаюсь на файл UserModel.php, который лежит в папке models, которая находится на уровень ниже index.php
Это зависит от того какой автозагрузчик и какие правила соответствия имен классов и файлов ты используешь. По PSR-4 неймспейсы надо называть с большой буквы так что твой неймспейс models не соответствует им. Также, лучше писать в единственном числе, не models, а Model\User (Model\UserModel это как масло масляное)
>>494727
> RewriteCond %(HTTP_HOST)%(REQUEST_URI) '!-f'
Это условие, говорящее дложны ли мы применять правило ниже или нет. Это условие склеивает имя хоста и путь (например для запроса http://example.com/news/list получается example.com/news/list) и проверяет есть ли такой файл. Если нет то правило ниже выполняется.
-f значит «если файл существует то выполнить правло ниже»
!-f это отрицание, «если файл не существует, выполнить правило»
Описание на англ http://httpd.apache.org/docs/2.4/rewrite/
Статья на русском http://habrahabr.ru/company/sprinthost/blog/129560/
> Подскажи как это сделать,
Также как и обычный просмотр, надо в функцию поиска передавать сортировку, offset и limit. И при подсчете общено числа записей надо считать только записи соответствующие фразе для поиска.
> Или вообще переделать метод searchStudents так чтоб в него попадал еще выбор сортировки и ее направление?
Да, а еще offset/limit
Чтобы проверить, что ты правильно меня понял, вот тебе мини-задачка (а если не что-то не понял, то задавай уточняющие вопросы):
Представь что у тебя есть сайт с объявлениями. Представь что на нем есть форма поиска объявлений. В ней можно искать объявления по одним или нескольким параметрам:
— тип объявления: сниму, сдам, куплю или продам или несколько типов сразу
— площадь квартиры от X до Y
— расположена рядом с метро X, Y или Z (можно выбрать 1 или больше станций)
— расположена в районе X
— до метро не более X метров
— цена от X до Y
— число комнат от X до Y
— размещено не более чем X дней назад
Поиск может вестись по нескольким критериям сразу (а можно не использовать поиск и показать все объявления), например:
— показать все объявления
— показать все объявления типа «сдам» или «продам», для квартир в которых от 2 до 4 комнат, площадью от 0 до 100 кв .м
— показать все объявления размещенные не более 14 дней назад, о квартирах рядом с метро Арбатская или Парк Победы
Результаты поиска могут сортироваться по одной из колонок (дата, цена, расстояние до метро) и отображаются постранично.
Напиши заголовок функции поиска объявлений в базе. Саму функцию писать не требуется, только заголовок, в одну строчку, например:
findApartments($type, $city)
Задача разумеется с небольшим подвохом :) Хочу посмотреть как ты будешь решать эту проблему. И попробуй сделать как можно проще, не усложняй ничего.
Кстати, другие аноны, вас приглашаю тоже попробовать решить. Мне кажется, из этого могла бы получиться хорошая задачка для собеседования, и не требующая много времени, надо всего-то написать одну строчку, но по ней можно понять о знаниях и опыте человека.
Чтобы проверить, что ты правильно меня понял, вот тебе мини-задачка (а если не что-то не понял, то задавай уточняющие вопросы):
Представь что у тебя есть сайт с объявлениями. Представь что на нем есть форма поиска объявлений. В ней можно искать объявления по одним или нескольким параметрам:
— тип объявления: сниму, сдам, куплю или продам или несколько типов сразу
— площадь квартиры от X до Y
— расположена рядом с метро X, Y или Z (можно выбрать 1 или больше станций)
— расположена в районе X
— до метро не более X метров
— цена от X до Y
— число комнат от X до Y
— размещено не более чем X дней назад
Поиск может вестись по нескольким критериям сразу (а можно не использовать поиск и показать все объявления), например:
— показать все объявления
— показать все объявления типа «сдам» или «продам», для квартир в которых от 2 до 4 комнат, площадью от 0 до 100 кв .м
— показать все объявления размещенные не более 14 дней назад, о квартирах рядом с метро Арбатская или Парк Победы
Результаты поиска могут сортироваться по одной из колонок (дата, цена, расстояние до метро) и отображаются постранично.
Напиши заголовок функции поиска объявлений в базе. Саму функцию писать не требуется, только заголовок, в одну строчку, например:
findApartments($type, $city)
Задача разумеется с небольшим подвохом :) Хочу посмотреть как ты будешь решать эту проблему. И попробуй сделать как можно проще, не усложняй ничего.
Кстати, другие аноны, вас приглашаю тоже попробовать решить. Мне кажется, из этого могла бы получиться хорошая задачка для собеседования, и не требующая много времени, надо всего-то написать одну строчку, но по ней можно понять о знаниях и опыте человека.
Все, по списку студентов я все замечания исправил, можешь проверять
https://github.com/V3N0m21/StudentList
А задачу я бы наверно делал так
findApartments(SearchParams $search, $sort, $dir, $start, $end)
Но я не уверен нужно ли создавать новый объект для параметров поиска, не излишнее ли это усложнение?
То что ты написал, я понял.
Как прописать, чтобы подключить свои классы через злоебучий композер - пока нет. На два дня застопорилась работа над файлообменником из-за этого.
>Задача разумеется с небольшим подвохом :)
Мне слегка надоели эти ваши подвохи, я их уже видеть не могу.
Метод должен принимать в качестве параметра экземпляр класса, отвечающего за сбор данных из формы, и ниипёт.
Хорошо у нас в мухосранях, никто не ебет джунам мозги: есть готовые работы, чтобы показать свой уровень - ты принят. Нет - гуляй вася. Даже если ты задрачивал полгода теорию по оповским ссылкам.
Никаких тупых вопросов уровня >>470285 . Такое впечатление эти ебланы морочат голову от нечего делать, плюс вялый траленк)
CREATE TABLE IF NOT EXISTS meter
(
id int AUTO_INCREMENT PRIMARY KEY,
one varchar,
two varchar,
three varchar,
four varchar
);\t
INSERT INTO meter (id, one, two, three, four) VALUES
(1, 11, \t'...', \t'...',\t'...'),
(2, 22, \t'...', \t'...',\t'...'),
(3, 33, \t'...', \t'...',\t'...'),
(4, 11, \t'...', \t'...',\t'...'),
(5, 22, \t'...', \t'...',\t'...'),
(6, 33, \t'...', \t'...',\t'...')
Там знаки табуляции, да.
Если у тебя какая-то колонка принимает только значения, перечисленные в списке, то нужно использовать тип enum
http://www.mysql.ru/docs/man/ENUM.html
>вот так вот повторялись
Как "вот так"?
Ты имеешь ввиду зависимость значения от четности?
1, 4, 7, ... = 11
2, 5, 8, ... = 22
3, 6, 9, ... = 33
Тогда нужно использовать целочисленный остаток от деления 4 % 3 = 1; 5 % 3 = 2; 6 % 3 = 0;
Ты лучше скажи, в чем постановка задачи. Что описывает эта таблица? По-моему, ты как-то через жопу делаешь, можно решить правильнее и красивее.
Да, я уже, кажется, нашёл способ лучше.
У меня это была таблица с показаниями счётчиков, которая должна ежемесячно заполняться новыми показаниями одних и тех же счётчиков. Она содержала в себе серийники, которые и должны были быть этим повторяющимся полем. Я вынес в отдельную таблицу серийники и теперь просто оттуда буду брать их, должно взлететь.
Что я делаю не так?
Структура проекта: в корне сайта index.php, папка vendor с этим говном и моя папка classes.
Composer.json
"autoload": {
"psr-4": {
"Classes\\": "classes/"
}
}
В index.php
$model = new \Classes\FileModel;
Говорит, класс Classes\\FileModel not found.
Слим и прочие вещи, добавленные автоматически, загружаются без проблем.
Что нужно писать в composer.json?
p.s. Просьба объяснить по-человечески, не надо кидать ссылки на мутную документацию, написанную мудаками.
Эту галиматью https://getcomposer.org/doc/04-schema.md#autoload я уже читал, там даются плохие примеры.
>When autoloading a class like Foo\\Bar\\Baz a namespace prefix Foo\\ pointing to a directory src/ means that the autoloader will look for a file named src/Bar/Baz.php and include it if present.
Где эта папка src/ находится? Внутри vendor/, или в корне проекта, у черта на куличках? Я должен догадываться?
Исхожу из того, что в корне сайта. Прописал как в посте выше - не работает.
По этой ссылке http://onedev.net/post/176
следующий код тоже не работает
$loader->addPsr4('Classes\\', __DIR__ . '/classes/');
Потому что это просто пиздец какой-то, никаких внятных инструкций в интернете.
https://github.com/Integer64/myTestSite.dev/tree/master/vecktor_OOP
Оп переделал почти все.
Но я не понял, почему не нужно использовать наследование в классах сценариях.
> class VecktorVersion1 extends Vecktor{
> class VecktorVersion2 extends Vecktor{
> class VecktorVersion3 extends Vecktor{
Все равно же используются метод класса Vecktor для вывода таблички.????
>>495423
>>495426
Ах, ОКАЗЫВАЕТСЯ нужно было во-первых в файлах классов объявить неймспейсы, во-вторых еще и в командной строке дернуть какую-то опцию composer dump-autoload -o, чтобы он заново сгенерировал файл автозагрузки. Это видимо подразумевалось само собой, ага.
Еще раз передаю привет матерям людей, которые пишут руководства и статьи вроде тех, что мне подсунул опчик.
ОП, по твоим ссылкам собачий кал, не одобряю:
1) https://getcomposer.org/doc/04-schema.md#autoload
неполная и неясная информация. Я например так и не понял: "classmap" в автозагрузке используется для тех файлов классов, что названы не по понятиям psr-4?
У меня работает, во всяком случае.
2) Тут вообще коммуняка, судя по фавикон. http://onedev.net/post/176 , дает справочную информацию, ничего не объясняет
3) http://habrahabr.ru/post/149678/ описан старый psr-0, пропущены некоторые моменты: объявление неймспейсов в файлах классов (ну хорошо, это я протупил, что не догадался, хотя какого хрена я должен догадываться?), и не сказано о том, что нужно заново сгенерировать автолодер командой dump-autoload -o, из-за чего я потратил полдня.
Возвращаюсь к старому доброму формату видеоуроков, где все подробно объясняется.
https://www.youtube.com/watch?v=VGSerlMoIrY
Итак, настроил я с горем пополам htaccess так, чтобы он вызывал скрипт когда обращаешься напрямую к несуществующему тамбнейлу. Из этого поста я было подумал, что теперь то всё будет работать само по себе: <img> обращается к несуществующей превьюшке, вызывается скрипт, превьюшка создается, и на главной странице каким-то чудесным образом без всяких перезагрузок всё будет отлично выводится. Но, очевидно, что это так не работает. Превью создается только когда вручную в адресную строку вбить адрес до файла вроде site.ru/thumbnails/image.jpg а как без перебора всех файлов в папке сделать так, чтобы при заходе на страницу превью автоматически создавались я ума не приложу.
Как не потерять знаки препинания? Я думаю, тут нужно /PREG_SPLIT_DELIM_CAPTURE добавить, но как-то не вышло. Ну и всё остальное как сделать лучше чем есть.
> Но я не уверен нужно ли создавать новый объект для параметров поиска, не излишнее ли это усложнение?
Не усложнение. Класс во-первых позволяет описать в нем все возможные параметры поиска, во-вторых позволяет добавлять методы для работы с ними. Также в будущем его можно расширять. Ну и этот объект можно передать в шаблон чтобы выставить значения элементов формы.
> $data
Если ты хотел сократить, лучше было назвать $mapper. Ну и лучше конечно не сокращать и писать $studentMapper. Твой редактор наверняка все равно поддерживает автодополнение и руками имя надо писать только в первый раз.
> $paginator = new Paginator;
> $pages = $paginator->countPages($rows);
> $currentItem = $paginator->setPages($current,$rows);
Наверно, число страниц и номер текущей лучше передавать сразу в конструктор. А ты тут 2 раза зачем-то $rows передаешь.
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L9
> &search=<?php echo $search?>
при подстановке данных в URL надо делать urlencode, который заменяет спецсимволы процентным кодированием ( https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Иначе, сам подумай, что если в $search встретятся символы вроде &, # ? Они все сломают.
Также ты можешь использовать функцию http_build_query (рекомендуется) которая сама собирает строку запроса из массива и все правильно экранирует.
Конкретно в своем случае, чтобы не загромождать шаблон копипастой, я бы вынес сборку ссылки в функцию вот так:
<a href="<?= html(getSortingLink($search, $dir, $column)) ?>">
(вообще это хорошая идея выносить генерацию ссылок в функции или методы класса-помощника — так и код читается лучше и менять формат ссылок потом проще).
Все это я дописал на страницу с задачей.
Чтобы убедиться что ты понимаешь как правильно передавать и экранировать любые символы, реши мини-задачку:
---------------
Сделай страницу с формой из textarea и кнопки отправки. Никакого оформления и CSS не требуется, просто черный текст на белом фоне. При вводе любого текста и нажатия кнопки текст должен появиться внизу под textarea. Текст должен точно соответствовать введенному, корректно отображать все символы, включая пробелы и переводы строк (тут тебе поможет тег pre), точно так как их ввел пользователь. Проверь что сочетания вроде
%20%20
<b>test
&amp;
"'\<>
&t=1&
Отображаются ровно в том же виде как введены.
После того, как ты это сделаешь, добавь еще кое-что. Кроме текста, надо выводить ссылку вида script.php?text=....., которая содержит введенный текст и открыв которую мы можем увидеть его на странице.
------------------
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L9
> search=<?php echo $search?>
> <?=$students[$i]->name?>
Все выводимые данные надо пропускать через htmlspecialchars, иначе получишь XSS уязвимость. Тут данные из базы, но это все равно не надежно. Если тебе лень писать каждый раз htmlspecialchars .. ENT_QUOTES, сделай вспомогательную функцию html() или h().
> <?php foreach ($students as $i => $student) : ?>
> <td> <?=$students[$i]->name?></td>
$i тут не нужен, лучше писать $student->name
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L35
Эта строка слишком длинная и нечитаемая, вынеси-ка генерацию ссылки в функцию.
Также, если у нас всего одна страница, пагинацию выводить не требуется. Также, текущая страница должна быть подсвечена.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L35
> header("Location: /?notify=saved");
После редиректа надо делать die() и не пытаться вывести форму, так как эту форму все равно никто не увидит.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L5
> $token = $student->generatePassword(5);
Это несерьезно. Ставь минимум 16 символов, также мне не нравится что ты для CSRF токена используешь объект-студента и метод генерации пароля. Я думаю, генерацию случайного кода надо просто вынести в отдельную функцию.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L48
> public function authStudent($password)
> public function setToken($token)
Класс Студент только хранит информацию о студенте. Это не его задача, заниматься авторизацией и тем более работать с куками. Вынеси это в отдельные функции или класс.
Аналогично, стоит вынести в функцию код, который генерирует и обновляет CSRF куку.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L45
HTML код должен быть в шаблоне
> AND NOT password='$password'";
Есть оператор «не равно», <>
Также, мне все равно не нравится что ты вставляешь переменные в запрос. Это плохо смотрится и легко ошибиться. Почему плейсхолдеры не используешь?
> $result = $result->num_rows;
Чтобы найти есть ли запись или нет, лучше делать запрос SELECT COUNT(×), тогда сразу видно что тебя интересует именно число.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L56
> $query = "SELECT FROM Students WHERE password='$password'";
тут SQL инъекция. Надо использовать плейсхолдеры и по моему в прошлый раз я про них писал.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L87
Тут лишний, бессмысленный real_escape_string
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L165
> public function searchStudents($string = '', $sort,$dir,$current = 1)
> public function countSearchStudents ($string = '')
В этих функциях не проверяется результат выполнения функций mysqli. После preapre и execute должны стоять if и выброс исключений.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L14
> ^[А-Яа-яЁё\s']
Что насчет Римского-Корсакова?
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L3
> #if (class_exists($class. '.php')) {
Тут должно быть не class_exists, а file_exists
В общем, пока основные вопросы к безопасности сайта. Вот еще я проверил твой код роботом, и он пару замечаний нашел:
-----------------------
Кажется, ты не используешь строгий режим в MySQL. Зря. MySQL более тщательно проверяет твои запросы и вместо предупреждений (которые ты не увидишь) выдает ошибки при попытке вставить неправильные данные. Ну к примеру, если у тебя есть колонка типа varchar(200) и ты попытаешься вставить в нее строку из 300 символов, в нестрогом режиме MySQL молча отрежет лишнее (и в базе окажется обрезанная строка), а в строгом выдаст ошибку.
Использование строгого режима экономит твое время на исправление неправильно вставленных данных. Статья на хабре: http://habrahabr.ru/post/116922/
Включить строгий режим можно сделав при соединении с БД запрос SET sql_mode='STRICT_ALL_TABLES'.
В файле ./lib/Student.php:
В методе Student#setAttributes аргумент $data можно пометить тайп хинтом array.
> $data
Если ты хотел сократить, лучше было назвать $mapper. Ну и лучше конечно не сокращать и писать $studentMapper. Твой редактор наверняка все равно поддерживает автодополнение и руками имя надо писать только в первый раз.
> $paginator = new Paginator;
> $pages = $paginator->countPages($rows);
> $currentItem = $paginator->setPages($current,$rows);
Наверно, число страниц и номер текущей лучше передавать сразу в конструктор. А ты тут 2 раза зачем-то $rows передаешь.
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L9
> &search=<?php echo $search?>
при подстановке данных в URL надо делать urlencode, который заменяет спецсимволы процентным кодированием ( https://ru.wikipedia.org/wiki/URL#.D0.9A.D0.BE.D0.B4.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_URL ). Иначе, сам подумай, что если в $search встретятся символы вроде &, # ? Они все сломают.
Также ты можешь использовать функцию http_build_query (рекомендуется) которая сама собирает строку запроса из массива и все правильно экранирует.
Конкретно в своем случае, чтобы не загромождать шаблон копипастой, я бы вынес сборку ссылки в функцию вот так:
<a href="<?= html(getSortingLink($search, $dir, $column)) ?>">
(вообще это хорошая идея выносить генерацию ссылок в функции или методы класса-помощника — так и код читается лучше и менять формат ссылок потом проще).
Все это я дописал на страницу с задачей.
Чтобы убедиться что ты понимаешь как правильно передавать и экранировать любые символы, реши мини-задачку:
---------------
Сделай страницу с формой из textarea и кнопки отправки. Никакого оформления и CSS не требуется, просто черный текст на белом фоне. При вводе любого текста и нажатия кнопки текст должен появиться внизу под textarea. Текст должен точно соответствовать введенному, корректно отображать все символы, включая пробелы и переводы строк (тут тебе поможет тег pre), точно так как их ввел пользователь. Проверь что сочетания вроде
%20%20
<b>test
&amp;
"'\<>
&t=1&
Отображаются ровно в том же виде как введены.
После того, как ты это сделаешь, добавь еще кое-что. Кроме текста, надо выводить ссылку вида script.php?text=....., которая содержит введенный текст и открыв которую мы можем увидеть его на странице.
------------------
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L9
> search=<?php echo $search?>
> <?=$students[$i]->name?>
Все выводимые данные надо пропускать через htmlspecialchars, иначе получишь XSS уязвимость. Тут данные из базы, но это все равно не надежно. Если тебе лень писать каждый раз htmlspecialchars .. ENT_QUOTES, сделай вспомогательную функцию html() или h().
> <?php foreach ($students as $i => $student) : ?>
> <td> <?=$students[$i]->name?></td>
$i тут не нужен, лучше писать $student->name
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L35
Эта строка слишком длинная и нечитаемая, вынеси-ка генерацию ссылки в функцию.
Также, если у нас всего одна страница, пагинацию выводить не требуется. Также, текущая страница должна быть подсвечена.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L35
> header("Location: /?notify=saved");
После редиректа надо делать die() и не пытаться вывести форму, так как эту форму все равно никто не увидит.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L5
> $token = $student->generatePassword(5);
Это несерьезно. Ставь минимум 16 символов, также мне не нравится что ты для CSRF токена используешь объект-студента и метод генерации пароля. Я думаю, генерацию случайного кода надо просто вынести в отдельную функцию.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L48
> public function authStudent($password)
> public function setToken($token)
Класс Студент только хранит информацию о студенте. Это не его задача, заниматься авторизацией и тем более работать с куками. Вынеси это в отдельные функции или класс.
Аналогично, стоит вынести в функцию код, который генерирует и обновляет CSRF куку.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L45
HTML код должен быть в шаблоне
> AND NOT password='$password'";
Есть оператор «не равно», <>
Также, мне все равно не нравится что ты вставляешь переменные в запрос. Это плохо смотрится и легко ошибиться. Почему плейсхолдеры не используешь?
> $result = $result->num_rows;
Чтобы найти есть ли запись или нет, лучше делать запрос SELECT COUNT(×), тогда сразу видно что тебя интересует именно число.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L56
> $query = "SELECT FROM Students WHERE password='$password'";
тут SQL инъекция. Надо использовать плейсхолдеры и по моему в прошлый раз я про них писал.
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L87
Тут лишний, бессмысленный real_escape_string
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L165
> public function searchStudents($string = '', $sort,$dir,$current = 1)
> public function countSearchStudents ($string = '')
В этих функциях не проверяется результат выполнения функций mysqli. После preapre и execute должны стоять if и выброс исключений.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L14
> ^[А-Яа-яЁё\s']
Что насчет Римского-Корсакова?
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L3
> #if (class_exists($class. '.php')) {
Тут должно быть не class_exists, а file_exists
В общем, пока основные вопросы к безопасности сайта. Вот еще я проверил твой код роботом, и он пару замечаний нашел:
-----------------------
Кажется, ты не используешь строгий режим в MySQL. Зря. MySQL более тщательно проверяет твои запросы и вместо предупреждений (которые ты не увидишь) выдает ошибки при попытке вставить неправильные данные. Ну к примеру, если у тебя есть колонка типа varchar(200) и ты попытаешься вставить в нее строку из 300 символов, в нестрогом режиме MySQL молча отрежет лишнее (и в базе окажется обрезанная строка), а в строгом выдаст ошибку.
Использование строгого режима экономит твое время на исправление неправильно вставленных данных. Статья на хабре: http://habrahabr.ru/post/116922/
Включить строгий режим можно сделав при соединении с БД запрос SET sql_mode='STRICT_ALL_TABLES'.
В файле ./lib/Student.php:
В методе Student#setAttributes аргумент $data можно пометить тайп хинтом array.
> Хорошо у нас в мухосранях, никто не ебет джунам мозги: есть готовые работы, чтобы показать свой уровень - ты принят. Нет - гуляй вася. Даже если ты задрачивал полгода теорию по оповским ссылкам.
Но ведь это скорее всего не вакансии программиста, а вакансии верстальщика с умением натягивать верстку на вордпресс. Для этого тебе не надо делать файлообменники (хотя на мой взгляд это очень простая задача), тебе стоило бы сделать наши задачи по HTML/CSS, потом изучить JS/DOM/jQuery, потом изучить одну или несколько CMS и сделать для себя (или найти на фрилансе заказы на верстку и взять их демпингом) несколько простых сайтов. И ты бы попал на столь желанную работу.
Но мне неинтересно готовить натягивальщиков верстки. Мы не HTML-тред и не ориентируемся на минимальный уровень. Мы тут все же в первую очередь подготавливаем нормальных разработчиков, которые смогут сами писать хороший ООП код. Если таких вакансий в твоем городе нет, ты можешь рассмотреть варианты удаленной работы, фриланса, переезда в другой город. Тогда знания из нашего треда тебе пригодятся.
Ну и я вижу из твоего сообщения, что ты недоволен. Но подумай, стоит ли злиться на меня или наш тред? Я просто помогаю учиться тем, кто этого хочет, не я определяю кадровую и экономическую ситуацию в твоем городе и не я виноват что ты там живешь.
Возвращаясь к композеру.
В композере ты просто прописываешь корневой неймспейс твоих классов (он может быть пустой) и корневую папку (относительно корня проекта, она по моему тоже может быть пустой или например быть чем-то вроде "lib"). Соответственно автозагрузчик будет знать что класс в этом неймспейсе лежат в этой папке.
Я выше дал пример:
> Это договоренность, что мы кладем класс с неймспейсом
> MyLibrary\A\B\C\D
> в файл
> my-library/src/A/B/C/D.php
Тут корневой неймспейс это 'MyLibrary', а корневая папка для этого неймспейса "my-library/src". Автозагрузчик отрезает от полного имени класса корневой неймспейс (остается \A\B\C\D) и далее делает из огрызка имя файла.
В твоем случае (у тебя же не библиотека) ты не обязан делать корневой неймспейс, ты вполне можешь например сделать его пустым.
> Хорошо у нас в мухосранях, никто не ебет джунам мозги: есть готовые работы, чтобы показать свой уровень - ты принят. Нет - гуляй вася. Даже если ты задрачивал полгода теорию по оповским ссылкам.
Но ведь это скорее всего не вакансии программиста, а вакансии верстальщика с умением натягивать верстку на вордпресс. Для этого тебе не надо делать файлообменники (хотя на мой взгляд это очень простая задача), тебе стоило бы сделать наши задачи по HTML/CSS, потом изучить JS/DOM/jQuery, потом изучить одну или несколько CMS и сделать для себя (или найти на фрилансе заказы на верстку и взять их демпингом) несколько простых сайтов. И ты бы попал на столь желанную работу.
Но мне неинтересно готовить натягивальщиков верстки. Мы не HTML-тред и не ориентируемся на минимальный уровень. Мы тут все же в первую очередь подготавливаем нормальных разработчиков, которые смогут сами писать хороший ООП код. Если таких вакансий в твоем городе нет, ты можешь рассмотреть варианты удаленной работы, фриланса, переезда в другой город. Тогда знания из нашего треда тебе пригодятся.
Ну и я вижу из твоего сообщения, что ты недоволен. Но подумай, стоит ли злиться на меня или наш тред? Я просто помогаю учиться тем, кто этого хочет, не я определяю кадровую и экономическую ситуацию в твоем городе и не я виноват что ты там живешь.
Возвращаясь к композеру.
В композере ты просто прописываешь корневой неймспейс твоих классов (он может быть пустой) и корневую папку (относительно корня проекта, она по моему тоже может быть пустой или например быть чем-то вроде "lib"). Соответственно автозагрузчик будет знать что класс в этом неймспейсе лежат в этой папке.
Я выше дал пример:
> Это договоренность, что мы кладем класс с неймспейсом
> MyLibrary\A\B\C\D
> в файл
> my-library/src/A/B/C/D.php
Тут корневой неймспейс это 'MyLibrary', а корневая папка для этого неймспейса "my-library/src". Автозагрузчик отрезает от полного имени класса корневой неймспейс (остается \A\B\C\D) и далее делает из огрызка имя файла.
В твоем случае (у тебя же не библиотека) ты не обязан делать корневой неймспейс, ты вполне можешь например сделать его пустым.
> Никаких тупых вопросов
Ну в некоторых компаниях тебя вообще могут попросить сбалансировать черно-красное дерево. Попробуй в Яндекс устроиться например.
>>495278
Если в таблице мног оповторяющихся значений, вопрос правильно ли она спроектирована?
>>495423
> Где эта папка src/ находится? Внутри vendor/, или в корне проекта, у черта на куличках? Я должен догадываться?
путь указывается относительно папки, где лежит composer.json. Там это написано в самом начале раздела:
> Under the psr-4 key you define a mapping from namespaces to paths, relative to the package root.
> relative to the package root.
package root это и есть корень проекта, где лежит composer.json (почему он называется package? что за пакет? это потому что composer.json используется в библиотеках и фреймворках для описания их зависимостей и правил автозагрузки, а библиотеки распространяются как «пакеты», отсюда такое название).
В папке vendor твоего кода быть не может так как эта папка для установки внешних библиотек и в ней не должно быть ни одного твоего файла. Она полностью принадлежит композеру.
> Исхожу из того, что в корне сайта. Прописал как в посте выше - не работает.
Проверь имена файлов и классов.
>>495505
> ОКАЗЫВАЕТСЯ нужно было во-первых в файлах классов объявить неймспейсы,
Да, иначе класс идет в глобальный неймспейс. Я же тебе написал выше, что неймспейс это не папка и ты выбираешь его произвольно. Но есть договоренность что мы храним классы в папках которые соответствуют именам неймспейсов.
> во-вторых еще и в командной строке дернуть какую-то опцию composer dump-autoload
Я об этом по моему 2 раза упомянул, ты не очень внимательно читаешь: >>493021 , >>494396
Конечно, от того что ты поменяешь composer.json само ничего не изменится, надо вызвать композер чтобы он перегенерировал что нужно. Точно также, если ты добавил библиотеку в список, надо вызвать composer update для ее установки.
> Я например так и не понял: "classmap" в автозагрузке используется для тех файлов классов, что названы не по понятиям psr-4?
classmap это для старых библиотек, не соответствующих стандартам, композер просто сканирует весь проект и создает список вида 'имя класса -> имя файла'. То есть это не твой бро.
Там еще есть опция files которая позволяет инклудить файлы с функциями (так как автозагрузка работает только с классами, а не с функциями).
> описан старый psr-0, пропущены некоторые моменты
да, это старая статья. Лучше всего официальная документация.
> объявление неймспейсов в файлах классов (ну хорошо, это я протупил, что не догадался, хотя какого хрена я должен догадываться?)
предполагалось что ты прочтешь мануал PHP по неймспейсам прежде чем ими пользоваться. Я конечно должен был дать ссылку, исправляюсь, прочти это:
http://php.net/manual/ru/language.namespaces.php
Кстати, в PHP очень хорошая, подробная документация и в отличие от других языков (Руби, Питон), она еще и переведена на русский. Не забудь порадоваться каждый раз когда открываешь мануал.
В общем предлагаю тебе искать хорошие стороны, например порадоваться что ты смог узнать много нового про неймспейсы, автозагрузку, композер и не зря потратил время.
>>495426
Да, наверно надо будет, тема важная, а при поиск выпадает всякое старье.
> Никаких тупых вопросов
Ну в некоторых компаниях тебя вообще могут попросить сбалансировать черно-красное дерево. Попробуй в Яндекс устроиться например.
>>495278
Если в таблице мног оповторяющихся значений, вопрос правильно ли она спроектирована?
>>495423
> Где эта папка src/ находится? Внутри vendor/, или в корне проекта, у черта на куличках? Я должен догадываться?
путь указывается относительно папки, где лежит composer.json. Там это написано в самом начале раздела:
> Under the psr-4 key you define a mapping from namespaces to paths, relative to the package root.
> relative to the package root.
package root это и есть корень проекта, где лежит composer.json (почему он называется package? что за пакет? это потому что composer.json используется в библиотеках и фреймворках для описания их зависимостей и правил автозагрузки, а библиотеки распространяются как «пакеты», отсюда такое название).
В папке vendor твоего кода быть не может так как эта папка для установки внешних библиотек и в ней не должно быть ни одного твоего файла. Она полностью принадлежит композеру.
> Исхожу из того, что в корне сайта. Прописал как в посте выше - не работает.
Проверь имена файлов и классов.
>>495505
> ОКАЗЫВАЕТСЯ нужно было во-первых в файлах классов объявить неймспейсы,
Да, иначе класс идет в глобальный неймспейс. Я же тебе написал выше, что неймспейс это не папка и ты выбираешь его произвольно. Но есть договоренность что мы храним классы в папках которые соответствуют именам неймспейсов.
> во-вторых еще и в командной строке дернуть какую-то опцию composer dump-autoload
Я об этом по моему 2 раза упомянул, ты не очень внимательно читаешь: >>493021 , >>494396
Конечно, от того что ты поменяешь composer.json само ничего не изменится, надо вызвать композер чтобы он перегенерировал что нужно. Точно также, если ты добавил библиотеку в список, надо вызвать composer update для ее установки.
> Я например так и не понял: "classmap" в автозагрузке используется для тех файлов классов, что названы не по понятиям psr-4?
classmap это для старых библиотек, не соответствующих стандартам, композер просто сканирует весь проект и создает список вида 'имя класса -> имя файла'. То есть это не твой бро.
Там еще есть опция files которая позволяет инклудить файлы с функциями (так как автозагрузка работает только с классами, а не с функциями).
> описан старый psr-0, пропущены некоторые моменты
да, это старая статья. Лучше всего официальная документация.
> объявление неймспейсов в файлах классов (ну хорошо, это я протупил, что не догадался, хотя какого хрена я должен догадываться?)
предполагалось что ты прочтешь мануал PHP по неймспейсам прежде чем ими пользоваться. Я конечно должен был дать ссылку, исправляюсь, прочти это:
http://php.net/manual/ru/language.namespaces.php
Кстати, в PHP очень хорошая, подробная документация и в отличие от других языков (Руби, Питон), она еще и переведена на русский. Не забудь порадоваться каждый раз когда открываешь мануал.
В общем предлагаю тебе искать хорошие стороны, например порадоваться что ты смог узнать много нового про неймспейсы, автозагрузку, композер и не зря потратил время.
>>495426
Да, наверно надо будет, тема важная, а при поиск выпадает всякое старье.
RewriteBase /
Но в Апаче 2.4 эта директива не нужна, она нужна только для 2.2 и в корне сайта ее можно не указывать по моему.
>>495505
Ну и молодец, если ты можешь читать английскую документацию и смотреть английские видео. Это тебе еще не раз пригодится и это преимущество перед теми, кто ограничен русской документацией, так как ее меньше и она старее.
Мне только не нравится что он в уроке папку models назвал с маленькой буквы, не по PSR4. И у него ошибка, когда он говорит: «достаточно написать use Codecourse\Repositories», нет, недостаточно, надо писать либо use Codecourse\Repositories\UserRepository полностью (as ... не требуется), либо в имени класса Repositories\UserRepository.
И заметь кстати что наш тред не как другие сайты и учебники, которые толкают всякое пыльное старье, мы используем современные подходы и инструменты (сам себя не похвалишь...).
Уточню еще по опции classmap:
> "classmap": ["src/", "lib/", "Something.php"]
Это значит просканировать перечисленные файлы и папки (относительно корня проекта) и запомнить соответствие между именами файлов и классов.
> что теперь то всё будет работать само по себе: <img> обращается к несуществующей превьюшке, вызывается скрипт, превьюшка создается, и на главной странице каким-то чудесным образом без всяких перезагрузок всё будет отлично выводится.
Так и должно быть. Если это не так, ты можешь открыть отладчик (Ctrl + Shift + I) в браузере, вкладку network, перезагрузить страницу и посмотреть что возвращают запросы к картинкам.
И твой скрипт после генерации превьюшки должен не только сохранить ее на диск, но и отдать в браузер с правильным Content-Type (браузер же ждет картинку). Он это делает?
> а как без перебора всех файлов в папке сделать так, чтобы при заходе на страницу превью автоматически создавались я ума не приложу.
Просто в <img> должна быть прописана правильная ссылка.
>>495316
Что-то у тебя много файлов в папке scripts. Как будто мы в прошлое до ООП вернулись. Давай-ка файлы PDO.php и check_student.php поместим внутрь ini.php
> if ($db->isPswrdInDB($password)) {
> $students = $db->isPswrdInDB($password);
> $student = $students[0];
Тут 2 обращения к базе подряд. Перепиши код чтобы функция вызывалась один раз, например сохраняя результат в переменную.
Вместо $student = $students[0]; сделай чтобы функция сразу возвращала то что нужно.
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php#L21
> require './template/main.php';
Я тебя уже по моему просил сделать чтобы шаблон подключался только один раз, а не несколько в разных местах (к тому же это может помешать ставить куки и выводить заголовки). Убери этот код. Шапку ты можешь подключить например из файла с шаблоном тела страницы (templates/list.php).
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php#L22
> if (isset($_GET['search'])) {
> include_once('./scripts/list_action.php');
Этого тут быть не должно. Убери этот код. Файл list_action.php подключается в index.php (при условии что $_GET['page'] == 'list') и одного раза вполне достаточно.
> https://github.com/Si0n/register3/blob/master/index.php#L13
> die('Произошла ошибка: <b>Страница не найдена.</b>');
Нужно добавить 2 вещи:
1) метатег meta charset (или заголовок Content-Type) задающий кодировку
2) заголовок header("HTTP/1.1 404 Not Found") который скажет роботам что это страница ошибки 404
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L3
> $x = 2;
Что такое $x? Назови переменную, чтобы было понятно что в ней хранится.
> $page = $p * $x -2;
это обычно называется offset (сколько записей надо пропустить от начала)
> $pageLinker= $link_start . http_build_query($link) . "\n";
Не очень понятно зачем тут перевод строки. Ссылка не может содержать пробелы или переводы строки.
И я тут подумал, а зачем нам эта возня со сборкой ссылок по кускам в index.php и str_replace? Сделай просто функцию которая генерирует ссылку на данную страницу с поиском (или без поиска) по заданному слову и пиши в шаблоне просто:
<a href="<?= htmlProtect(getPaginatorLink($search, $page, ...)) ?>">
Генерировать ссылки через функции намного удобнее чем вот так по кускам собирать разные переменные. Аналогично можно генерировать ссылки для сортировки таблицы по разным колонкам.
> <td>Местный(L)/Приезжий(N)</td>
Лучше бы конечно сразу писать текстом, а не буквами. Для этого достаточно добавить функцию, которая получает на вход букву и выводит слово. У функции должно быть понятное имя вроде getIsLocalText (упс, получилось не идеально, не зря говорят что придумывать названия одна из сложнейших вещей в программировании). Также, можно сделать метод в классе Student для этого. Аналогично с полом.
> https://github.com/Si0n/register3/blob/master/template/list.php#L31
По пагинации: если страница всего одна, выводить пагинацию не надо. Также, надо подсвечивать текущую страницу.
> https://github.com/Si0n/register3/blob/master/template/register.php#L18
> require 'scripts/form_fill.php';
Нет, так не пойдет, и в прошлый раз я тебе уже говорил это. Шаблон не должен вызывать обработчик формы. Это наоборот, обработчик формы может вызвать шаблон чтобы вывести форму. То, что у тебя, не соответствует MVC.
> https://github.com/Si0n/register3/blob/master/scripts/form_fill.php
> 'surname' => 'Ваша Фамилия',
Эти подсказки надо не подставлять в поля, а выводить через специальный атрибут placeholder: http://htmlbook.ru/html/input/placeholder
Их можно прописать прямо в шаблоне.
Так, в общем, вывод списка у тебя сделан неплохо. Не хватает только сортировки. Ну и по редактированию/регистрации, надо исправлять код.
>>495316
Что-то у тебя много файлов в папке scripts. Как будто мы в прошлое до ООП вернулись. Давай-ка файлы PDO.php и check_student.php поместим внутрь ini.php
> if ($db->isPswrdInDB($password)) {
> $students = $db->isPswrdInDB($password);
> $student = $students[0];
Тут 2 обращения к базе подряд. Перепиши код чтобы функция вызывалась один раз, например сохраняя результат в переменную.
Вместо $student = $students[0]; сделай чтобы функция сразу возвращала то что нужно.
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php#L21
> require './template/main.php';
Я тебя уже по моему просил сделать чтобы шаблон подключался только один раз, а не несколько в разных местах (к тому же это может помешать ставить куки и выводить заголовки). Убери этот код. Шапку ты можешь подключить например из файла с шаблоном тела страницы (templates/list.php).
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php#L22
> if (isset($_GET['search'])) {
> include_once('./scripts/list_action.php');
Этого тут быть не должно. Убери этот код. Файл list_action.php подключается в index.php (при условии что $_GET['page'] == 'list') и одного раза вполне достаточно.
> https://github.com/Si0n/register3/blob/master/index.php#L13
> die('Произошла ошибка: <b>Страница не найдена.</b>');
Нужно добавить 2 вещи:
1) метатег meta charset (или заголовок Content-Type) задающий кодировку
2) заголовок header("HTTP/1.1 404 Not Found") который скажет роботам что это страница ошибки 404
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L3
> $x = 2;
Что такое $x? Назови переменную, чтобы было понятно что в ней хранится.
> $page = $p * $x -2;
это обычно называется offset (сколько записей надо пропустить от начала)
> $pageLinker= $link_start . http_build_query($link) . "\n";
Не очень понятно зачем тут перевод строки. Ссылка не может содержать пробелы или переводы строки.
И я тут подумал, а зачем нам эта возня со сборкой ссылок по кускам в index.php и str_replace? Сделай просто функцию которая генерирует ссылку на данную страницу с поиском (или без поиска) по заданному слову и пиши в шаблоне просто:
<a href="<?= htmlProtect(getPaginatorLink($search, $page, ...)) ?>">
Генерировать ссылки через функции намного удобнее чем вот так по кускам собирать разные переменные. Аналогично можно генерировать ссылки для сортировки таблицы по разным колонкам.
> <td>Местный(L)/Приезжий(N)</td>
Лучше бы конечно сразу писать текстом, а не буквами. Для этого достаточно добавить функцию, которая получает на вход букву и выводит слово. У функции должно быть понятное имя вроде getIsLocalText (упс, получилось не идеально, не зря говорят что придумывать названия одна из сложнейших вещей в программировании). Также, можно сделать метод в классе Student для этого. Аналогично с полом.
> https://github.com/Si0n/register3/blob/master/template/list.php#L31
По пагинации: если страница всего одна, выводить пагинацию не надо. Также, надо подсвечивать текущую страницу.
> https://github.com/Si0n/register3/blob/master/template/register.php#L18
> require 'scripts/form_fill.php';
Нет, так не пойдет, и в прошлый раз я тебе уже говорил это. Шаблон не должен вызывать обработчик формы. Это наоборот, обработчик формы может вызвать шаблон чтобы вывести форму. То, что у тебя, не соответствует MVC.
> https://github.com/Si0n/register3/blob/master/scripts/form_fill.php
> 'surname' => 'Ваша Фамилия',
Эти подсказки надо не подставлять в поля, а выводить через специальный атрибут placeholder: http://htmlbook.ru/html/input/placeholder
Их можно прописать прямо в шаблоне.
Так, в общем, вывод списка у тебя сделан неплохо. Не хватает только сортировки. Ну и по редактированию/регистрации, надо исправлять код.
> Как не потерять знаки препинания?
preg_split удаляет то, что соответствует регулярке. Есть 2 варианта:
— сохранять его с помощью PREG_SPLIT_DELIM_CAPTURE (сохраняется только то что в регулярке помещено в круглые скобки, без них не работает)
— использовать утверждения, которые срабатывают если перед/после них есть знак, но не захватывают его и он возвращается вместе с предложением: http://php.net/manual/ru/regexp.reference.assertions.php
(кстати если ты внимательно читал условие задачи, там разрешается заменять знаки на точки, но я чувствую ты не хочешь их терять, это хорошо).
Также, второй цикл ставящий пробелы можно заменить на один preg_replace, подумай, как.
> foreach ($arr2 as &$value) {
> $result .= $value;
> }
В таких случаях надо использовать implode вместо цикла
> $arr1
Лучше называть переменную осмысленно, например $sentences. Вот хорошая статья по теме: http://learn.javascript.ru/write-unmain-code
MVC на сервере (PHP) и клиенте (JS) реализуется немного по-разному. backbone это для яваскрипта, Zend это для PHP.
Начать советую с фреймворка попроще, вроде Yii2. После него можешь за симфони 2 браться. А Zend 1 уже довлоьно старый, сейчас Zend 2 есть, но он по популярности уступает симфони 2.
там есть ссылка, ты можешь открыть сайт и порыться инспектором в браузере (Ctrl + Shift + I). Скорее всего либо WebGL (что значит будет работать не везде, а только где поддерживаемые драйвера и видеокарты) либо CSS transform3d (что опять же много где тормозит).
> Это яваскрипт?
Это в том числе яваскрипт.
Я кстати не люблю эти штуки, у меня на ноуте WebGL не работает, а transform3d работает не очень быстро.
> $defaultPayment += $defaultPayment * 0.25;
> $this->payment = $defaultPayment;
Лучше сразу писать $this->payment = $defaultPayment × 1.25; а не запутывать код лишними сложениями и присваиваниями.
Попробуем теперь проверить что будет при назначении/разжаловании из боссов. Протестируй такой код, мне кажется, он даст ошибку:
$employee = new Engineer(1, false);
$oldCoffee = ...;
$oldpayment = ...;
$oldPaper = ....;
$employee->setBoss(true);
$employee->setRank(2);
$employee->setBoss(false);
$employee->setRank(1);
$newCoffee = ...;
$newPayment = ...;
$newPaper = ...;
assert($oldCoffee == $newCoffee);
assert($oldPaper == $newPaper);
assert($oldPayment == $newPayment);
Я тебе еще раз напомню что можно просто не хранить итоговую зарплату, а вычислять ее при вызове getPayment и тогда проблемы с пересчетом решатся сами собой.
> Но я не понял, почему не нужно использовать наследование в классах сценариях.
мне кажется антикризисный менеджмент это внешнаяя по отношению к департаментам штука и логичнее делать его отдельным классом и применять к компании:
$anticrisis = new AnticrisisManagement();
$anticrisis->applyPlan1($vector);
В принципе твой вариант с наследованием решает задачу, но по моему он менее гибкий. Например твой антикризисный план нельзя применить к любой компании, так как он сам ее создает и наполняет работниками. Это менее гибкий код, в котором смешано несколько задач.
И наследование используется для однотипных вещей. Ты можешь унаследовать Инженера от Работника или Машину от Транспорта, но что в твоем случае наследуется, непонятно, нельзя наследовать АнтикризисноеУправлениеКомпанией от Компании. Мне кжается антикризисный менеджмент это отдельная сущность и не надо его смешивать с компанией. Мне кажется наследование использовать тут неправильно, это не соответствует всяким принципам ООП, вроде SOLID:
http://habrahabr.ru/post/208442/
> $defaultPayment += $defaultPayment * 0.25;
> $this->payment = $defaultPayment;
Лучше сразу писать $this->payment = $defaultPayment × 1.25; а не запутывать код лишними сложениями и присваиваниями.
Попробуем теперь проверить что будет при назначении/разжаловании из боссов. Протестируй такой код, мне кажется, он даст ошибку:
$employee = new Engineer(1, false);
$oldCoffee = ...;
$oldpayment = ...;
$oldPaper = ....;
$employee->setBoss(true);
$employee->setRank(2);
$employee->setBoss(false);
$employee->setRank(1);
$newCoffee = ...;
$newPayment = ...;
$newPaper = ...;
assert($oldCoffee == $newCoffee);
assert($oldPaper == $newPaper);
assert($oldPayment == $newPayment);
Я тебе еще раз напомню что можно просто не хранить итоговую зарплату, а вычислять ее при вызове getPayment и тогда проблемы с пересчетом решатся сами собой.
> Но я не понял, почему не нужно использовать наследование в классах сценариях.
мне кажется антикризисный менеджмент это внешнаяя по отношению к департаментам штука и логичнее делать его отдельным классом и применять к компании:
$anticrisis = new AnticrisisManagement();
$anticrisis->applyPlan1($vector);
В принципе твой вариант с наследованием решает задачу, но по моему он менее гибкий. Например твой антикризисный план нельзя применить к любой компании, так как он сам ее создает и наполняет работниками. Это менее гибкий код, в котором смешано несколько задач.
И наследование используется для однотипных вещей. Ты можешь унаследовать Инженера от Работника или Машину от Транспорта, но что в твоем случае наследуется, непонятно, нельзя наследовать АнтикризисноеУправлениеКомпанией от Компании. Мне кжается антикризисный менеджмент это отдельная сущность и не надо его смешивать с компанией. Мне кажется наследование использовать тут неправильно, это не соответствует всяким принципам ООП, вроде SOLID:
http://habrahabr.ru/post/208442/
Алсо
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/models/Vecktor.php#L192
> $length = $length - mb_strlen($string)+2;
Костыли-костылики? Если результат отрицательный, не надо просто делать str_repeat.
>я вижу из твоего сообщения, что ты недоволен
Это да, но можешь не обращать внимания.
Недовольство частично наигранное (где ваше чувство юмора, господа? неудивительно, что бабы вам не дают), направлено не к тебе, а против авторов некачественных документаций и статей-мануалов.
И правда, я полез по твоим ссылкам и невнимательно прочитал сами посты.
Нет, вот почему нигде не написано, что нужно каждый раз после модификации composer.json вызывать dump-autoload?
Может и написано, но я не нашел, значит написано бессвязно, не там где нужно.
Почему я узнаю об этом из только из треда и видео какого-то неизвестного блоггера?
Это определенно заговор.
>порадоваться что ты смог узнать много нового
Ага, за два дня узнал как прописать две строки кода.
На этот пост можешь не отвечать, он не несет в себе серьезных вопросов, да и вообще информативной нагрузки.
А можешь и отвечать. Я не прочь поболтать.
Кроме ошибок по моей вине, тут еще много левых сообщений. Хотелось бы понимать, про чё они, и как от них избавиться.
Это наверное неважные замечания о кривой конфигурации сервера? Игнорировать или исправлять?
[Fri Jun 12 04:34:17.461317 2015] [mpm_prefork:notice] [pid 1147] AH00169: caught SIGTERM, shutting down
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20121212+lfs/php_curl.dll' - /usr/lib/php5/20121212+lfs/php_curl.dll: cannot open shared object file: No such file or directory in Unknown on line 0
[Fri Jun 12 11:23:57.599687 2015] [mpm_prefork:notice] [pid 1160] AH00163: Apache/2.4.7 (Ubuntu) PHP/5.5.9-1ubuntu4.9 configured -- resuming normal operations
[Fri Jun 12 11:23:57.599846 2015] [core:notice] [pid 1160] AH00094: Command line: '/usr/sbin/apache2'
p.s. Почему я один засираю этот тред? Аж неудобно как-то.
Странно, что у самого популярного веб-яп такой медленный тред.
Все отмечают праздник. Да и тред давно в бамплиммите и скрыт от посторонних.
Спасибо, сохранил, буду думать.
Поправил по твоим замечаниям, есть вопрос по поводу spl_autoload_register в init.php
spl_autoload_register(function ($class) {
\tif (file_exists($class.'.php')) {
\trequire $class . '.php';
\t}
file_exists не находит StudentMapper.php, хотя они находятся в одной директории. Можешь подсказать почему? Я уже два часа играюсь, не могу понять
https://github.com/V3N0m21/StudentList
> https://github.com/Si0n/register3/blob/master/scripts/check_student.php#L21
> require './template/main.php';
>Я тебя уже по моему просил сделать чтобы шаблон подключался только один раз, а не несколько в разных местах (к тому же это может помешать ставить куки и выводить заголовки). Убери этот код. Шапку ты можешь подключить например из файла с шаблоном тела страницы (templates/list.php).
Именно этот шаблон один раз подключался или вообще все шаблоны?
В main.php у меня всё меню находится, не понимаю, что надо сделать и что не так сейчас именно с этим.
> но и отдать в браузер с правильным Content-Type (браузер же ждет картинку). Он это делает?
Дописал header с контентом, теперь при заходе на главную генерируются превьюшки. Одна проблема осталась: они не отображаются в момент создания и нужно перезагрузить страницу. Я так понял, так не должно быть? Или это нормально?
Ага, всё понял, что ты имел ввиду - я не смог отправить header(...) перед die().
Поставь в автозагрузчик var_dump($class) и var_dump(путь к файлу); и посмотри что выведется. Он скорее всего выведет относительный путь, который отсчитывается от текущей директории которую можноувидеть через var_dump(getcwd());
>>495874
Тебе надо подключать только один шаблон и только в конце скрипта.
>>495876
> Я так понял, так не должно быть? Или это нормально?
Это значит что твой скрипт отдает что-то неправильно. Сохрани ссылку на превьюшку, сотри превьюшки с диска, убери временно header Content-Type, и попробуй открыть эту ссылку чтобы увидеть что отдается в первый раз. Скорее всего там перед или после данных картинки идет какой-то текст, например ошибка или предупреждение. Достаточно одного пробела чтобы сломать картинку так как это бинарный файл.
Вот что выдает без header при обращении к несуществующей превьюшке в первый раз.
Попробовал на локальном сервере сделать такой трюк.
Без проблем редиректится на www.site.ru/index.php, который находится на самом деле по адресу www.site.ru/public_html/index.php
Но если нужно подключить другие скрипты, выдает 500 ошибку.
The server encountered an internal error or misconfiguration and was unable to complete your request.
[Fri Jun 12 16:37:38.467694 2015] [core:error] [pid 1349] [client 127.0.0.1:46333] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Так что оказывается никакого волшебства и настроек по умолчанию у апача нет, и чтобы папка public_html корректно заработала, надо что-то где-то прописать.
Я там еще слим использовал, так что может из-за него. Я пока смутно понимаю, как обрабатывается слимовский маршрут.
Пока решил вопрос от обратного, путем созданием папки protected с .htaccess (deny from all), как это сделано во фреймворке yii, например.
Но интересно, как реализовать первый способ с открытой папкой, как на хостингах.
Я тут подумал, для отладки можно отключить сохранение на диск или сохранять в левую папку, чтобы при обращении превьюшка всегда генерировалась заново. А потом, когда разберешься в чем дело, вернуть все обратно.
1) Почему Content-Length = 0 ? Это ты поставил?
2) Что в теле ответа (вкладка Response)? По идее там должны быть бинарные данные картинки, и без Content-Type они должны выглядеть как набор бессмысленных символов (можешь открыть любую картинку блокотом и посмотреть сам), вроде такого:
‰PNG
IHDR – –\b <qв gAMA ЇИ7Љй tEXtSoftware Adobe ImageReadyqЙe< ,IDATxЪм]\vґUЮ.rpDA@ЕG!>HСТ,K15џh(f–fEYi)б+5Нd‘
Ну а с нужным Content-Type эти данные выведутся не как текст, а как картинка.
Я подозреваю, что у тебя тело ответа пустое, то есть твой скрипт не отдает в браузер данные картинки, а надо отдавать. Тут есть 2 способа:
— сохранить сгенерированную картинку в строку, сохранить строку в файл и вывести через echo
— сохранить картинку на диск, а потом прочесть с диска и отдать в браузер. Это выглядит костыльно, но в PHP это проще реализовать.
«отдать данные в браузер» просто значит вывести бинарные данные картинки через echo (или readfile если ты хочешь вывести содержимое файла).
После того как ты наладишь вывод картинки, надо вернуть все назад и проверить что PHP скрипт запускается только первый раз. Это можно проверить по наличию заголовка X-Powered-By: PHP, он должен быть только при первом обращении к превьюшке.
Алсо, что PHP такой древний? PHP 5.3 очень старый, уже давно 5.6 есть.
выносить код за пределы document root это правильная идея. Повышает безопасность.
Это делается через настройку DocumentRoot в <VirtualHost> в конфиге Апача. Она должна указывать на public_html.
> Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Кривые настройки mod_rewrite, читай статью http://habrahabr.ru/company/sprinthost/blog/129560/
Для отладки можно включить опцию LogLevel debug и перезапустить Апач, он будет писать подробно как он обрабатывает правила в mod rewrite.
> Я пока смутно понимаю, как обрабатывается слимовский маршрут.
— С помощью htaccess ты перенаправляешь все запросы на index.php
— index.php запускается. ты создаешь Слим и с помощью $app->get говоришь какую функцию надо вызывать при том или ином URL
— затем ты вызвыаешь $app->run()
— Слим смотрит текущий URL в $_SERVER['REQUEST_URI'] и сравнивает с теми что ты задал через $app->get()
— если есть совпадение, вызывается твоя функция-обработчик, если нет то показывается страница 404
Ты можешь сам написать аналогичный роутер за 5 минут с помощью if:
$url = $_SERVER['REQUEST_URI'];
// Надо удалить из URL все что идет после знака вопроса чтобы URL с параметрами вроде /hello?x=1 работали
if ($url == '/hello') {
echo "Hello";
die();
} elseif ($url == '/goodbye') {
...
} else {
die("page not found");
}
Только выглядит он пострашнее чем код с использованием Слима, а так, то же самое.
Задавай уточняющие вопросы.
выносить код за пределы document root это правильная идея. Повышает безопасность.
Это делается через настройку DocumentRoot в <VirtualHost> в конфиге Апача. Она должна указывать на public_html.
> Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Кривые настройки mod_rewrite, читай статью http://habrahabr.ru/company/sprinthost/blog/129560/
Для отладки можно включить опцию LogLevel debug и перезапустить Апач, он будет писать подробно как он обрабатывает правила в mod rewrite.
> Я пока смутно понимаю, как обрабатывается слимовский маршрут.
— С помощью htaccess ты перенаправляешь все запросы на index.php
— index.php запускается. ты создаешь Слим и с помощью $app->get говоришь какую функцию надо вызывать при том или ином URL
— затем ты вызвыаешь $app->run()
— Слим смотрит текущий URL в $_SERVER['REQUEST_URI'] и сравнивает с теми что ты задал через $app->get()
— если есть совпадение, вызывается твоя функция-обработчик, если нет то показывается страница 404
Ты можешь сам написать аналогичный роутер за 5 минут с помощью if:
$url = $_SERVER['REQUEST_URI'];
// Надо удалить из URL все что идет после знака вопроса чтобы URL с параметрами вроде /hello?x=1 работали
if ($url == '/hello') {
echo "Hello";
die();
} elseif ($url == '/goodbye') {
...
} else {
die("page not found");
}
Только выглядит он пострашнее чем код с использованием Слима, а так, то же самое.
Задавай уточняющие вопросы.
>1) Почему Content-Length = 0 ? Это ты поставил?
Ноуп, я ничего такого не ставил, вроде.
>2) Что в теле ответа (вкладка Response)? По идее там должны быть бинарные данные картинки, и без Content-Type они должны выглядеть как набор бессмысленных символов (можешь открыть любую картинку блокотом и посмотреть сам)
Да, вкладка Response пустая.
Вот так выглядит скрипт (с хидером), на которой у меня стоит редирект при не существующей превьюшке http://ideone.com/Hx6bSY
> папки protected с .htaccess (deny from all), как это сделано во фреймворке yii, например.
Это менее надежное решение так как Deny from all можно переопределить во внутренних папках например. И надо не забывать закрывать так все папки первого уровня. Юи так делает из-за того что он рассчитан на любые хостинги и на пользователей которые не осилят сделать нужные настройки. Ну и если говорить о первом Юи, та вообще структура папок неудачная по нынешним меркам, так как код фреймворка перемешан с твоим. Сейчас фрйемворки ставят через композер в папку vendor, а твой код идет в основной папке. В Yii2 вроде так и сделали.
>>495808
> caught SIGTERM, shutting down
Это не ошибка просто сообщение о том что остановили Апач
> PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20121212+lfs/php_curl.dll' - /usr/lib/php5/20121212+lfs/php_curl.dll: cannot open shared object file: No such file or directory in Unknown on line 0
Это ошибка, у тебя расширение curl почему-то криво установлено или настроено. ВИдимо ты его неправильно установил.
В линуксе ты ставишь расширения 2 способами:
— если оно есть в виде пакета то пакетом (например через apt-get install php5-curl в дебиане/убунту)
— если нет то через pecl, там надо что-то натсроить, потом пишешь pecl install something, он скачивает и компилирует расширение
Руками ничего никуда копировать не надо.
> , я ничего такого не ставил, вроде.
Значит Апач поставил.
> $dir = scandir('images');
Это неправильно. Для проверки есть ли файл надо использовать file_exists а не странные обходные способы. Также, ты испольузешь относительный путь, а надежнее прописывать абсолютный, например относительно _ _ DIR _ _ который всегда указывает на папку с текущим файлом.
> echo "Ошибка. Изображения не существует $fname";
Без тега meta или кодировки в Content-Type буквы не будут читаться скорее всего. Также, надо добавлять код ответа вроде 500, например
header("HTTP/1.1 500 Internal Error");
Коды ответа: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP
> \theader('Content-Type: image/jpg');
> imagejpeg($tmp_img, "thumbnails/$fname");
Это сохраняет картинку на диск но не отдает в браузер. Браузер полуает только заголовок без тела картинки.
Кстати, COntent-Length тоже хорошо бы отдавать, это позволяет браузеру увидеть ошибку при обрыве соединения (так как браузер знает сколько байт должно придти). В этом заголовке передается длина картинки в байтах, получить ее можно прочитав размер файла либо если бинарные данные в строке, то через strlen (не mb_strlen, она считает символы а не байты).
В общем, тебе надо сделать то что я написал выше:
> Тут есть 2 способа:
> — сохранить сгенерированную картинку в строку, сохранить строку в файл и вывести через echo
> — сохранить картинку на диск, а потом прочесть с диска и отдать в браузер. Это выглядит костыльно, но в PHP это проще реализовать.
> \tif(strtolower($info['extension']=='jpg')){
Тип картинки надежнее определять по содержимому, а не расширению, например функцией getimagesize()
> \tif($width<$thumbWidth && $height<$thumbHeight){
> continue;
> }
continue только в цикле можно использовать
> $fname = $_GET['fname'];
Лучше бы имя файла не передавать отдельно, а брать из REQUEST_URI.
Советую потом показать код на проверку еще раз.
> , я ничего такого не ставил, вроде.
Значит Апач поставил.
> $dir = scandir('images');
Это неправильно. Для проверки есть ли файл надо использовать file_exists а не странные обходные способы. Также, ты испольузешь относительный путь, а надежнее прописывать абсолютный, например относительно _ _ DIR _ _ который всегда указывает на папку с текущим файлом.
> echo "Ошибка. Изображения не существует $fname";
Без тега meta или кодировки в Content-Type буквы не будут читаться скорее всего. Также, надо добавлять код ответа вроде 500, например
header("HTTP/1.1 500 Internal Error");
Коды ответа: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP
> \theader('Content-Type: image/jpg');
> imagejpeg($tmp_img, "thumbnails/$fname");
Это сохраняет картинку на диск но не отдает в браузер. Браузер полуает только заголовок без тела картинки.
Кстати, COntent-Length тоже хорошо бы отдавать, это позволяет браузеру увидеть ошибку при обрыве соединения (так как браузер знает сколько байт должно придти). В этом заголовке передается длина картинки в байтах, получить ее можно прочитав размер файла либо если бинарные данные в строке, то через strlen (не mb_strlen, она считает символы а не байты).
В общем, тебе надо сделать то что я написал выше:
> Тут есть 2 способа:
> — сохранить сгенерированную картинку в строку, сохранить строку в файл и вывести через echo
> — сохранить картинку на диск, а потом прочесть с диска и отдать в браузер. Это выглядит костыльно, но в PHP это проще реализовать.
> \tif(strtolower($info['extension']=='jpg')){
Тип картинки надежнее определять по содержимому, а не расширению, например функцией getimagesize()
> \tif($width<$thumbWidth && $height<$thumbHeight){
> continue;
> }
continue только в цикле можно использовать
> $fname = $_GET['fname'];
Лучше бы имя файла не передавать отдельно, а брать из REQUEST_URI.
Советую потом показать код на проверку еще раз.
То есть imagepng и imagejpg могут либо передавать изображение, либо сохранять на диск, но не обе эти вещи одновременно?
Есть ли вообще смысл в том, что я изучаю всю первую часть + раздел с регулярными выражениями?
Или типо для вёрстки мне и половину тут знать не надо?
Вот ссылка на ресурс: learn.javascript.ru
По-моему так и делал, через apt-get.
Вот у меня гугол даже сохранил в истории бложик, где я подсмотрел установку курла.
http://otakoyi.com/blog/ru/kak-ustanovit-php-curl-ubuntu-linux/
Ну ладно, это неважно.
>>495926
С виртуалхостом буду разбираться, ок.
Что касается mod_rewrite, я ничего не трогал в настройках, оно так и было!
Не, ну честно, все что я сделал после установки апача, это a2enmod rewrite, ну и в apache2.conf прописал Allow override All.
Ну хорошо, это мелочи. Ошибки не фатальные, на работу не влияют. Но конечно надо разобраться с настройками, ибо не комильфо, что оно срет ошибками в логи.
Для верстки вообще джаваскрипт знать не обязательно. Для фронт энда же в целом тебе конечно пригодится и регулярки в том числе. По регуляркам у ОПа как раз есть урок
http://archive-ipq-co.narod.ru/l1/regexp.html функции в жс, конечно, другие, а вот синтаксис регулярные выражений тот же что и в php.
Ну раз это учебник, а не справочник, то наверное так и задумано, что ты должен всё последовательно учить, а не пропускать и перепрыгивать темы.
Усидчивости у меня мало.
+ без практики я уже дня через 3 забываю то, что учил.
А какая практика по основам?
Ну сделал я допустим задание по подсчёту цифр в числе (или подобное говно из интернетов) и что мне это дало (кроме того, что узнал что такое parseInt()).
Вот я и думал, выучить основы и дальше уже идти практику и если будут вопрос - гуглить.
Можно так вообще стать хорошим программистом (таким способом, который я описал выше)?
В шапке треда есть задачки от ОПа на жс.
https://gist.github.com/codedokode/ce30e7a036f18f416ae0
Не знаю, правда, на какой уровень они расчитаны, я их еще не решал.
Ну прочитал я в википедии https://ru.wikipedia.org/wiki/CURL
cURL — свободная, кроссплатформенная служебная программа командной строки, позволяющая взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Программа cURL может автоматизировать передачу файлов или последовательность таких операций.
Каких операций? Я не понимаю это сухое определение. Что делает эта утилита? Мне снова приходится включать фантазию и домысливать недосказанное.
В случае с композером, скрипт (как я догадываюсь, php) обращается к оболочке (башу, например), а через нее к этой утилите, передавая ей параметры (URL, протокол, что-то там еще). Утилита соединяется по указанному протоколу с узлом и запрашивает с него данные (пакеты из composer.json).
Вот таким образом эти файлики оказываются в моей директории, будто я сам сходил на гитхаб по http и ручками их схоронил оттуда поштучно, или разархивировав.
Я правильно УГАДАЛ назначение этой утилиты?
Нет, мне нравится заниматься программированием, но материалы подаются отвратительно. Я гораздо больше времени трачу на поиск информации, чем на собственно учебу.
Ну ладно, не буду больше бугуртеть, а то вы тут народ непуганный, воспринимаете близко к серцу (лол, классная опечатка, не буду исправлять)
Оп, давай короче как придешь к успеху и будет время, напиши полный учебник. У тебя хорошо получается именно объяснять, что и для чего используется, зачем это нужно и как работает, а не так как это сейчас в документациях-справочниках и статейках, которыми я давлюсь
[code]
Хуйня_нейм - это кудрявый_термин1, используемый для кудрявый_термин2 через кудрявый термин3.
Используется при помощи набора заклинаний:
nabor_bukov + nabor_znakov + nabor_cifer
Прочитав эту статью, вы теперь знаете и умеете работать с хуйня_нейм.
[/code]
По идее верстка это только HTML/CSS (кстати по ним в Оп посте есть неплохие задачки). Но везде если ты посмотришь тредования в вакансиях, хотят еще знание JS, jQuery и умение пользоваться и писать плагины для всяких слайдеров, календариков и прочих вещей.
Так что изучать JS надо, но после или вместе с HTML/CSS.
Кстати у нас и на JS/DOM/jQuery задания есть.
Еще от верстальщиков может потребоаться умение натянуть верстку на CMS вроде вордпресса.
Ну и вообще, изучение верстки занимает ну максимум неделю-две-три. Согласись, специалист который потратил на обучение две недели, выглядит довольно сомнительно.
>>495935
Да
>>495942
Бложик кстати пишет неправильно. Достаточно указать
sudo apt-get install php5-curl
и дописать curl если тебе нужен клиент для командной строки (не имеющий отношения к PHP).
Но все равно, если бы ты так ставил, ошибки быть не должно. Ты явно что-то еще делал что испортило ситуацию.
В линуксе динамические библиотеки называются обычно вроде abc.so, а у тебя почему-то dll:
/usr/lib/php5/20121212+lfs/php_curl.dll
Ты явно что-то в конфиги не то вписал. У меня курл подключен в файле /etc/php5/apache2/conf.d/20-curl.ini сторочкой extension=curl.so (этот файл создался сам при установке)
Поищи все упоминания курла в конфигах: grep -i curl -R /etc/php5
Объяснение опций команды: http://explainshell.com/explain?cmd=grep+-i+curl+-R+%2Fetc%2Fphp5
Она должна тебе показать все строки, содержащие курл, тебе надо найти неправильную и удалить. для правки конфигов нужен sudo.
По идее верстка это только HTML/CSS (кстати по ним в Оп посте есть неплохие задачки). Но везде если ты посмотришь тредования в вакансиях, хотят еще знание JS, jQuery и умение пользоваться и писать плагины для всяких слайдеров, календариков и прочих вещей.
Так что изучать JS надо, но после или вместе с HTML/CSS.
Кстати у нас и на JS/DOM/jQuery задания есть.
Еще от верстальщиков может потребоаться умение натянуть верстку на CMS вроде вордпресса.
Ну и вообще, изучение верстки занимает ну максимум неделю-две-три. Согласись, специалист который потратил на обучение две недели, выглядит довольно сомнительно.
>>495935
Да
>>495942
Бложик кстати пишет неправильно. Достаточно указать
sudo apt-get install php5-curl
и дописать curl если тебе нужен клиент для командной строки (не имеющий отношения к PHP).
Но все равно, если бы ты так ставил, ошибки быть не должно. Ты явно что-то еще делал что испортило ситуацию.
В линуксе динамические библиотеки называются обычно вроде abc.so, а у тебя почему-то dll:
/usr/lib/php5/20121212+lfs/php_curl.dll
Ты явно что-то в конфиги не то вписал. У меня курл подключен в файле /etc/php5/apache2/conf.d/20-curl.ini сторочкой extension=curl.so (этот файл создался сам при установке)
Поищи все упоминания курла в конфигах: grep -i curl -R /etc/php5
Объяснение опций команды: http://explainshell.com/explain?cmd=grep+-i+curl+-R+%2Fetc%2Fphp5
Она должна тебе показать все строки, содержащие курл, тебе надо найти неправильную и удалить. для правки конфигов нужен sudo.
Кстати, ты знал что можно открыть лог в терминале и он будет сам обновляться?
tail -f /var/log/messages
(если нет доступа то добавь себя в группу adm которая дает право читать логи)
Для tail можно указать сразу несколько имен файлов через пробел или звездочки.
также, ты можешь следить за логом с помощью less: less +F /var/log/xxx
Для выхода из режима слежения жми ctrl +c, для возврата по моему надо нажать Shift + F (большую букву F).
> Что касается mod_rewrite, я ничего не трогал в настройках, оно так и было!
Ты htaccess в public_html перенес? DocumentRoot поменял?
Увидеть текущий конфиг и виртуальные хосты можно командой
apache2ctl -t -D DUMP_VHOSTS
(может понадобиться sudo)
Двачую, бро. Большинство справочного материала просто отвратительно организовано, что-то более-менее годно сделано только в самых популярных вещах и то не во всех. Как будто специально пишут так, чтобы максимально непонятно было. Причем когда все же находишь что-нибудь нормальное, то потом удивляешься, насколько же все просто. Вот неужели так сложно нормальную документацию писать, почему каждый дебил считает, что всем должно быть интересно в их говне ковыряться?
Получается всё то надо учить(что я скинул по джаваскрипту)?
Есть какие-то годные самоучители по HTML и CSS (что бы не 4 версия, но и основы были)?
А, блин, я думал ты про какие-нибудь глобальные настройки сервера, а это для конкретного хоста.
Да, я тупо перенес индекс.пхп в public_html, и надеялся что оно заработает без танцев с бубном, ага.
Ну хорошо, пойду учиться. А то я тут сру больше, чем читаю мануалы. Хотя пользы с них мало, если честно. Без твоих объяснений ничего не было бы понятно. (задобрил)
>>495964
curl.so подключен, пикрелейтед
стоп, какого члена у меня там dll в php.ini?
Видимо я от усталости скопипастил виндовые настройки.
Тьфу.
curl это библиотека для скачивания файлов по различным протоколам (например FTP, SFTP) и отправки HTTP-запросов. Обычно исплоьзуется именно второе. То есть курл это клиент HTTP, который может отправлять HTTP-запросы и получать на них ответ. Твой браузер тоже кстати является HTTP клиентом.
Как ты наверно уже догадался, неплохо понимать что такое и как работает HTTP чтобы пользоватся курлом.
Сам по себе курл доступен как не связанная с PHP программа команжной строки, используется примерно так:
curl 'http://example.com/'
Но для PHP на его основе сделано расширение которое добавляет эти функции (скачивание файлов и HTTP-клиент) в PHP.
> скрипт (как я догадываюсь, php) обращается к оболочке (башу, например), а через нее к этой утилите, передавая ей параметры (URL, протокол, что-то там еще).
Нет, тут имеется в виду не утилита-курл, а расширение-курл которое добавляет в PHP функции curl_...: http://php.net/manual/ru/book.curl.php
Вызывать внешний процесс не очень эффективно и неудобно.
> Я правильно УГАДАЛ назначение этой утилиты?
ТОлько это не утилита, а расширение. Но да, она используется для скачивания файлов по HTTP.
Композер работает чуть сложнее. Он сначала обращается к репозиторию (хранилищу информации о пакетах) packagist.org (зайди, посмотри) и скачивает с него список пакетов с информацией, какой они версии, где их можно скачать, какие пакеты от каких зависят и с какими конфликтуют.
По умолчанию композер использует packagist но ты можешь поменять список репозиториев, например доабвить свой приватный репозиторий с приватными пакетами (это вариант для больших компаний у которых они есть).
Затем он анализирует твой composer.json, смотрит прописанные там версии пакетов (там может быть написана не конкретная версия, а условие, например любой пакет старше чем X.Y) и анализируя их зависимости, определяет какие конкретно версии каких пакетов надо установить.
Затем он смотрит где можно получить эти пакеты, скачивает и распаковывает. пакеты могут быть из разных источников: репозиторий в гитхабе, zip-архив на сайте и т.д. Поддерживаемые источники немного описаны тут:
https://getcomposer.org/doc/04-schema.md#repositories
> The following repository types are supported: composer, vcs, pear, package
https://getcomposer.org/doc/05-repositories.md
В слуае с гитхабом, кстати композер пробует 2 варианта: скачать zip через API или если не получится, склонировать git репозиторий и выбрать (checkout) нужную версию.
Кстати, если ты когда-нибудь захочешь сделать свою библиотеку, тебе надо будет просто добавить composer.json в нее, описывающий зависимости, автозагрузку, имя автора и тд, и добавить ссылку на проект в packagist, а он добавит эту информацию в свой список.
> Нет, мне нравится заниматься программированием, но материалы подаются отвратительно.
Часто проблемы с пониманием возникают если ты чего-то не знаешь или пропустил.
— Чтобы работать с курлом надо знать HTTP. Справедливости ради, общее представление о HTTP стоит получить даже перед тем как вообще писать скрипты для браузера на PHP. Ведь именно по протоколу HTTP взаимодействует браузер и веб-сервер.
— насчет композера, я думаю, те кто его делали, имели опыт с менеджерами пакетов в других языках (а они везде есть: в Руби, Питоне, Java итд. В Линуксе программы тоже ставятся через менеджер пакетов, на смартфонах через магазин приложений, только виндусоиды до сих пор руками что-то качают) и соответственно им принцип работы кажется очевидным. Ну не написали пока документацию для чайников, есть только статьи в интернете.
Вот есть какая-то статья вводного уровня на русском: http://habrahabr.ru/post/145946/
curl это библиотека для скачивания файлов по различным протоколам (например FTP, SFTP) и отправки HTTP-запросов. Обычно исплоьзуется именно второе. То есть курл это клиент HTTP, который может отправлять HTTP-запросы и получать на них ответ. Твой браузер тоже кстати является HTTP клиентом.
Как ты наверно уже догадался, неплохо понимать что такое и как работает HTTP чтобы пользоватся курлом.
Сам по себе курл доступен как не связанная с PHP программа команжной строки, используется примерно так:
curl 'http://example.com/'
Но для PHP на его основе сделано расширение которое добавляет эти функции (скачивание файлов и HTTP-клиент) в PHP.
> скрипт (как я догадываюсь, php) обращается к оболочке (башу, например), а через нее к этой утилите, передавая ей параметры (URL, протокол, что-то там еще).
Нет, тут имеется в виду не утилита-курл, а расширение-курл которое добавляет в PHP функции curl_...: http://php.net/manual/ru/book.curl.php
Вызывать внешний процесс не очень эффективно и неудобно.
> Я правильно УГАДАЛ назначение этой утилиты?
ТОлько это не утилита, а расширение. Но да, она используется для скачивания файлов по HTTP.
Композер работает чуть сложнее. Он сначала обращается к репозиторию (хранилищу информации о пакетах) packagist.org (зайди, посмотри) и скачивает с него список пакетов с информацией, какой они версии, где их можно скачать, какие пакеты от каких зависят и с какими конфликтуют.
По умолчанию композер использует packagist но ты можешь поменять список репозиториев, например доабвить свой приватный репозиторий с приватными пакетами (это вариант для больших компаний у которых они есть).
Затем он анализирует твой composer.json, смотрит прописанные там версии пакетов (там может быть написана не конкретная версия, а условие, например любой пакет старше чем X.Y) и анализируя их зависимости, определяет какие конкретно версии каких пакетов надо установить.
Затем он смотрит где можно получить эти пакеты, скачивает и распаковывает. пакеты могут быть из разных источников: репозиторий в гитхабе, zip-архив на сайте и т.д. Поддерживаемые источники немного описаны тут:
https://getcomposer.org/doc/04-schema.md#repositories
> The following repository types are supported: composer, vcs, pear, package
https://getcomposer.org/doc/05-repositories.md
В слуае с гитхабом, кстати композер пробует 2 варианта: скачать zip через API или если не получится, склонировать git репозиторий и выбрать (checkout) нужную версию.
Кстати, если ты когда-нибудь захочешь сделать свою библиотеку, тебе надо будет просто добавить composer.json в нее, описывающий зависимости, автозагрузку, имя автора и тд, и добавить ссылку на проект в packagist, а он добавит эту информацию в свой список.
> Нет, мне нравится заниматься программированием, но материалы подаются отвратительно.
Часто проблемы с пониманием возникают если ты чего-то не знаешь или пропустил.
— Чтобы работать с курлом надо знать HTTP. Справедливости ради, общее представление о HTTP стоит получить даже перед тем как вообще писать скрипты для браузера на PHP. Ведь именно по протоколу HTTP взаимодействует браузер и веб-сервер.
— насчет композера, я думаю, те кто его делали, имели опыт с менеджерами пакетов в других языках (а они везде есть: в Руби, Питоне, Java итд. В Линуксе программы тоже ставятся через менеджер пакетов, на смартфонах через магазин приложений, только виндусоиды до сих пор руками что-то качают) и соответственно им принцип работы кажется очевидным. Ну не написали пока документацию для чайников, есть только статьи в интернете.
Вот есть какая-то статья вводного уровня на русском: http://habrahabr.ru/post/145946/
Может ты что-то пропустил важное? Вы же, аноны, все спешите куда-то, не хотите теорию изучать. Ну условно говоря, перед курлом надо изучить HTTP, перед изучением фреймворков надо изучить ООП и тд. Может в этом проблема?
Часто документация пишется для людей с определенными знаниями, часто, да, документации не хватает, что поделать. Так было всегда, сколько я помню.
Вот-вот. Алсо, в линуксе по моему лучше не править php.ini (тем более их там два, для cli и apache2), а добавить свой файл, наример vasya.ini в /etc/php5/conf.d — тогда при обновлении проблем не будет.
А, хотя папок conf.d там тоже две. Ну дебианщики начудили. Ну тогда ты можешь создать в одной папке vasya.ini, а в другой поставить симлинк или жесткую ссылку на него и не надо будет редактировать 2 файла.
>Я не понимаю это сухое определение. Что делает эта утилита?
Вообще, если есть время, можешь почитать офииальную документацию:
— по утилите командной строки, все подробно расписано в официальном мануале (я нашел его по слову man curl, если у тебя линукс и установлен curl то эта справка доступна в командной строке): http://curl.haxx.se/docs/manpage.html
> curl is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP). The command is designed to work without user interaction.
— по расширению для PHP, на русском: http://php.net/manual/ru/book.curl.php
Все есть, но придется потратить немного времени на чтение, это да.
Кстати, утилиту командной строки curl удобно исплоьзовать когда надо например руками отправить запрос к какому-нибудь REST API и посмотреть что придет.
Может я и пропустил что-то важное, но чаще всего дело именно в отвратительной подаче. Частенько бывает, что читаю/смотрю какой-нибудь урок и нихуя не понятно. Следом открываю другой, где рассказывается то же самое, но другими словами и сразу с первых секунд все становится предельно ясно. Проблема в том, что такие уроки не часто встречаются.
И вообще, естественно я тороплюсь, т.к. у меня больше нет возможности сидеть спокойно и учить по часику-два в день что-то. Приходится минимум часов 6-10 уделять этому делу. В голове каша, но ничего поделать с этим не могу.
а вообще, ты же собрался в вёрстку? в /wrk есть тред специальный, вот их гайд
https://gist.github.com/codedokode/58ebc90bd006baf4b35c
Верстальщики без знания яваскрипта и jQuery (а еще желательно умения натягивать верстку на CMS) мало востребованы.
> А какая практика по основам?
В ОП посте есть неплохие задачи в том числе по основам JS, и даже робот который умеет проверять некоторые из них. Если ты их решишь, тебе яваскрипт будет ночами сниться и ты точно его не забудешь.
> Вот я и думал, выучить основы и дальше уже идти практику и если будут вопрос - гуглить.
Сначала надо выучить язык, иначе ты будешь не программист, а копипастер кода из интернета.
Можно тогда мне-дауну расписать пошагово, с чего начинать (+ хорошую лит-ру на русском по этому) и чем заканчивать (в идеале хочу стать веб разработчик зная хорошо фронтенд, но специализируясь на бекенде + что бы можно было легко найти фриланс).
Спасибо заранее.
Начни с HTML/CSS, если ты их не очень хорошо знаешь, выше там кто-то вбросил ссылку на файл из /wrk треда: https://github.com/num13ru/verstka-thread
Продолжи JS/DOM/jQuery, сайт learn.javascript.ru, задания в ОП посте
Потом берись за вордпресс (этот шаг можно пропустить если тебя не особо интересует натягивание верстки на CMS)
Потом за PHP, ООП. MVC, фреймворк Yii 2.
Этого я думаю хватит.
Спасибо ОП.
Потихоньку начинаю думать парадигмами ООП и отвыкать от процедурного мышления.
Переделал.
https://github.com/Integer64/myTestSite.dev/tree/master/vecktor_OOP
Нужно больше критики и рекомендаций.
Мне вообще есть смысл заниматься программированием??
https://github.com/Si0n/register3
Добавил функцию для создания ссылок в пагинатор, также добавил возможность сортировки результатов на текущей странице, вроде исправил проблемы с шаблонами когда из шаблона загружался не шаблон, а скрипт, и исправления по мелочи в регистрации-редактировании, ещё нашел баг с тем, что не редактировался пол и локализация студента.
Я пока только мимоходом успел поглядеть, я вижу что там уже почти все готово (но замечания я все равно найду конечно), а ты не мог бы еще удалить или перенести в папку old неиспользуемые файлы? errors.sql, скрипты и шаблоны которые больше не используются, чтобы я их не смотрел даже.
Я их наверное удалю все за ненадобностью, а .sql потом перезалью с исправлениями, там я знаю, что у меня типы данных не все которые нужны, year не использован для хранения года.
>где-то в коде шаблона мы пишем:
<img src="<?= Thumbnail::link('/image/uploads/1234567.png', 400, 300, Thumbnal::MODE_CROP) ?>">
>и генерируется ссылка (например: /thumbnail/1.png), которая >вернет уменьшенную картинку, шириной не более 400px, высотой >не более 300.
То я не могу понять, как мне передать аргументы с главной страницы в функцию скрипта с помощью .htaccess
Подключи файл с классом Thumbnail и все. В местах, где нужно показать превьюшку вызываешь метод link и он возвращает ссылку на оную.
Хорошо, допустим я это сделал (хотя зачем для этого нужен отдельный метод, если он заменяет всего одну строчку с прямым путём к фалу?). Но с аргументами то как быть? Предполагается, что метод не только возвращает ссылку, но еще и делает само превью, иначе зачем мне передавать ему высоту с шириной и кроп мод?
Ну так ты в скобках через запятую аргументы и передаешь. А потом уже в самом методе обрабатывай картинку с учетом переданных аргументов.
Ты меня совсем запутал. Зачем мне передавать ей аргументы, если она только ссылку на превью отдает, а скрипт, который эти превьшки создает вызывается через .htaccess и он эти аргументы не получит? Я и спрашивю, как мне их ему передать?
Эмм, чет я не помню, что там в задаче было. Нафиг .htaccess нужен то? Не проще ли просто проверять в методе, существует ли уже превьюшка и если существует, то возвращать ссылку на нее?
> как мне передать аргументы с главной страницы в функцию скрипта с помощью .htaccess
Через URL очевидно. То есть допустим у тебя ссылка на картинку имеет вид
/images/lala/1.jpg
В ссылке на превьюшку ты кодируешь путь к картинке и параметры превьюшки:
/thumbs/crop-100x100/images/lala/1.jpg
(это пример)
Соответственно скрипт генерации разбирает URL и понимает какую превьюшку сгенерировать.
А функция Thumbnail::link как раз генерирует такую ссылку имя ссылку на оригинал и параметры превьюшки.
>>496359
> хотя зачем для этого нужен отдельный метод, если он заменяет всего одну строчку с прямым путём к фалу?
Потому что руками ссылку генерировать не очень правильно, да и человек может легко забыть в каком порядке что идет, и если ты вдруг захочешь поменять формат ссылки, ты замуччаешься это делать. В общем, ссылку однозначно стоит генерировать функцией.
> Предполагается, что метод не только возвращает ссылку, но еще и делает само превью, иначе зачем мне передавать ему высоту с шириной и кроп мод?
Он подставляет эти параметры в ссылку, как иначе скрипт обрезки узнает размер? только из URL.
> как мне передать аргументы с главной страницы в функцию скрипта с помощью .htaccess
Через URL очевидно. То есть допустим у тебя ссылка на картинку имеет вид
/images/lala/1.jpg
В ссылке на превьюшку ты кодируешь путь к картинке и параметры превьюшки:
/thumbs/crop-100x100/images/lala/1.jpg
(это пример)
Соответственно скрипт генерации разбирает URL и понимает какую превьюшку сгенерировать.
А функция Thumbnail::link как раз генерирует такую ссылку имя ссылку на оригинал и параметры превьюшки.
>>496359
> хотя зачем для этого нужен отдельный метод, если он заменяет всего одну строчку с прямым путём к фалу?
Потому что руками ссылку генерировать не очень правильно, да и человек может легко забыть в каком порядке что идет, и если ты вдруг захочешь поменять формат ссылки, ты замуччаешься это делать. В общем, ссылку однозначно стоит генерировать функцией.
> Предполагается, что метод не только возвращает ссылку, но еще и делает само превью, иначе зачем мне передавать ему высоту с шириной и кроп мод?
Он подставляет эти параметры в ссылку, как иначе скрипт обрезки узнает размер? только из URL.
http://habrahabr.ru/post/260201/
Разумеется, сначала вам надо стать просто джуниором прежде чем то что там описано, делать.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Employee.php#L28
Комментарий устаревший.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Employee.php#L91
> default:
> break;
Это плохая идея так как при неверном ранге мы просто выходим из функции и возвращаеи null. Не надо молчать, выбрось исключение:
default:
throw new Exception("invalid rank: $x");
Урок по исключениям: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Ну и вместо 2 switch там можно было написать один и сделать домножение на 1.5 для босса.
> if($objectOne->getBoss() || $objectTwo->getBoss()){
Если ты хотел сделать чтобы боссы шли последними в очередь на понижение, то неправильно сделал. Надо сделать так:
если A босс, а B не босс то вернуть ...
если A не босс, а B босс то вернуть ...
иначе сравнить ранги
Ведь функция сравнения должна вернуть в каком порядке идут эти 2 объекта.
Ну и по моему проще вообще не выбирать боссов при выборе тех, кого хочешь уволить.
В методе
https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/models/AnticrisisManagement.php#L162
нет проверки что работник 1 или 2 ранга, эта функция легко может повысить и с 3 ранга до 4 (тут кстати помогла бы проверка выбрасывающая иключения в setRank() при установке неправильного ранга)
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Employee.php#L28
Комментарий устаревший.
> https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/classes/Employee.php#L91
> default:
> break;
Это плохая идея так как при неверном ранге мы просто выходим из функции и возвращаеи null. Не надо молчать, выбрось исключение:
default:
throw new Exception("invalid rank: $x");
Урок по исключениям: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
Ну и вместо 2 switch там можно было написать один и сделать домножение на 1.5 для босса.
> if($objectOne->getBoss() || $objectTwo->getBoss()){
Если ты хотел сделать чтобы боссы шли последними в очередь на понижение, то неправильно сделал. Надо сделать так:
если A босс, а B не босс то вернуть ...
если A не босс, а B босс то вернуть ...
иначе сравнить ранги
Ведь функция сравнения должна вернуть в каком порядке идут эти 2 объекта.
Ну и по моему проще вообще не выбирать боссов при выборе тех, кого хочешь уволить.
В методе
https://github.com/Integer64/myTestSite.dev/blob/master/vecktor_OOP/models/AnticrisisManagement.php#L162
нет проверки что работник 1 или 2 ранга, эта функция легко может повысить и с 3 ранга до 4 (тут кстати помогла бы проверка выбрасывающая иключения в setRank() при установке неправильного ранга)
> if (isset($_COOKIE['password']))
> {
> $cookiePass = $_COOKIE['password'];
> }
Это неудачный код, так как если нет куки, то переменная не существует. Это плохо, когда переменная может существовать, а может и нет, переделай чтобы она существовала в любом случае, просто была пустой если куки нет.
Соответственно таких конструкций if (isset($cookiePass)) в твоем коде быть не должно (но использовать isset для проверки наличия элемента в массиве можно).
Тут ты вынужден разбить проверку на 2 части: проверка в Student и проверка уникальности email. Как видишь, помещать проверку внутрь самого студента оказалось не очень удачной идеей и лучше сделать ее отдельным классом или функцией.
> $success = TRUE;
> foreach ($errors as $error)
> {
> if ($error == TRUE)
Непонятен смысл этой проверки, ведь у тебя в массиве ошибок лежат строки, а не true/false. не проще ли просто проверить пуст массив или нет?
> https://github.com/Si0n/register3/blob/master/scripts/form_fill.php
Я не очень понимаю, зачем этот файл и зачем в нем превращение объекта в массив. Я считаю, это не нужно и проще в шаблон с формой передавать сам объект Student (а если его нет то создать пустой и передать)
Также, я думаю что нам не нужен файл form_fill.php. Для вывода формы регистрации мы можем использовать reg.php
Также, вот это не очень правильно:
> 'surname' => 'Ваша Фамилия',
зачем по умолчанию вписывать в поле текст если его потом приходится стирать руками? Не лучше ли оставить поле пустым?
Если ты хотел сделать подсказку, то она делается через атрибут placeholder.
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L3
> $offset = 2;
Почему offset по умолчанию равен 2? Не понимаю.
> if ($p > 1)
> {
> $page = $p × $offset -2;
> } else {
> $page = 0;
> }
По моему тут неправильные формулы. И номер страницы вряд ли может быть равен нулю, он считается с единицы.
> $link = array('search' => 'replaceSearch',
> 'order' => 'replaceOrder',
> 'p' => 'replaceP');
> $tablePanelHeadingText = "Результаты поиска: {$search}. ";
Это все как-то сложно и запутанно. Зачем нам нужен шаблон ссылки с странными словами в нем? Почему мы не можем генерировать ссылку с помощью функции без всяких шаблонов?
> https://github.com/Si0n/register3/blob/master/scripts/functions.php#L12
> $staticLink = str_replace('replaceSearch', $search, $staticLink);
Здесь ты не делаешь urlencode при вставке слова из поиска в URL. Также, вместо того чтобы несколько раз использовать str_replace, удобнее использовать strtr принимающий массив замен.
Ну и эту функцию надо бы переделать чтобы она работала без шаблонов, а создавала ссылку с нуля.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L6
> spl_autoload_register(function ($class) {
> include './lib/'.$class . '.php';
В автозагрузчике нужен if (file_exists(..)), я по моему об этом уже писал.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L19
> $student = $db->isPswrdInDB($password)[0];
Надо во-первых, переименовать эту функцию (так как функции is... возвраают true/false а не массив), во-вторых сделать чтобы она сразу возвращала объект и [0] был не нужен.
> https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L68
> $stud = $srchStudents->fetchAll();
> $count = count($stud);
Вот это вообще неправильно, ты выкачиваешь всех студентов из базы в PHP только чтобы посчитать их количество и выбросить данные. Надо использовать SELECT COUNT(x) для таких случаев.
Если ты плохо знаешь SQL, у нас в ОП посте есть задания по нему, и там по моему есть ссылка на туториал.
> https://github.com/Si0n/register3/blob/master/lib/Student.php#L97
> $code = sha1($code);
Зачем нужна эта строчка? Или объясни, что она делает или давай ее удалим.
Когда ты будешь проверять имена и фамилии, помни что в России фамилия может содержать дефис, апостроф и состоять из нескольких слов: О'Генри, Сан Антуан Кристоф, Римский-Корсаков. Существуют фамилии из одной буквы, например китайская «Ю».
Хочешь проверять адрес email с помощью регулярных выражений? Прочти статьи: http://habrahabr.ru/post/55820/, http://habrahabr.ru/post/175375/
Теперь перейдем к HTML и интерфейсу.
- Подсказки надо делать через атрибут placeholder
- Вкладки сверху (регистрация и список студентов) не везде выводятся и активная вкладка никак не выделяется
- При клике по слову «Приезжий» в кружочке не появляется точечка, а должна появляться. Почитай про HTML тег label: http://htmlbook.ru/html/label
Тебе надо засунуть input и подпись к нему в label.
- Аналогично, подписи полей должны быть сделаны тегом label, чтобы при клике по ним курсор ставился в поле. Тег label специально придуман для подписей к полям.
- сама форма вся перекошена и подписи к полям больше самих полей.
Я тебе советую взять за основу код отсюда: http://getbootstrap.com/css/#forms и адаптировать его для твоей формы (например Horizontal form может тебе подойти)
- основную кнопку «Отправить данные» стоит сделать синим цветом и обычно ее располагают справа. Также, стоит переименовать ее в «Зарегистрироваться» («Сохранить» при редактировании)
- Функция «Посмотреть мои данные» /index.php?page=inspect у меня показывает пустые значения. Форма редактирования тоже.
Кстати, если ты хочешь лучше изучить HTML/CSS, у нас есть неплохие задания по ним в ОП-посте.
> if (isset($_COOKIE['password']))
> {
> $cookiePass = $_COOKIE['password'];
> }
Это неудачный код, так как если нет куки, то переменная не существует. Это плохо, когда переменная может существовать, а может и нет, переделай чтобы она существовала в любом случае, просто была пустой если куки нет.
Соответственно таких конструкций if (isset($cookiePass)) в твоем коде быть не должно (но использовать isset для проверки наличия элемента в массиве можно).
Тут ты вынужден разбить проверку на 2 части: проверка в Student и проверка уникальности email. Как видишь, помещать проверку внутрь самого студента оказалось не очень удачной идеей и лучше сделать ее отдельным классом или функцией.
> $success = TRUE;
> foreach ($errors as $error)
> {
> if ($error == TRUE)
Непонятен смысл этой проверки, ведь у тебя в массиве ошибок лежат строки, а не true/false. не проще ли просто проверить пуст массив или нет?
> https://github.com/Si0n/register3/blob/master/scripts/form_fill.php
Я не очень понимаю, зачем этот файл и зачем в нем превращение объекта в массив. Я считаю, это не нужно и проще в шаблон с формой передавать сам объект Student (а если его нет то создать пустой и передать)
Также, я думаю что нам не нужен файл form_fill.php. Для вывода формы регистрации мы можем использовать reg.php
Также, вот это не очень правильно:
> 'surname' => 'Ваша Фамилия',
зачем по умолчанию вписывать в поле текст если его потом приходится стирать руками? Не лучше ли оставить поле пустым?
Если ты хотел сделать подсказку, то она делается через атрибут placeholder.
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L3
> $offset = 2;
Почему offset по умолчанию равен 2? Не понимаю.
> if ($p > 1)
> {
> $page = $p × $offset -2;
> } else {
> $page = 0;
> }
По моему тут неправильные формулы. И номер страницы вряд ли может быть равен нулю, он считается с единицы.
> $link = array('search' => 'replaceSearch',
> 'order' => 'replaceOrder',
> 'p' => 'replaceP');
> $tablePanelHeadingText = "Результаты поиска: {$search}. ";
Это все как-то сложно и запутанно. Зачем нам нужен шаблон ссылки с странными словами в нем? Почему мы не можем генерировать ссылку с помощью функции без всяких шаблонов?
> https://github.com/Si0n/register3/blob/master/scripts/functions.php#L12
> $staticLink = str_replace('replaceSearch', $search, $staticLink);
Здесь ты не делаешь urlencode при вставке слова из поиска в URL. Также, вместо того чтобы несколько раз использовать str_replace, удобнее использовать strtr принимающий массив замен.
Ну и эту функцию надо бы переделать чтобы она работала без шаблонов, а создавала ссылку с нуля.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L6
> spl_autoload_register(function ($class) {
> include './lib/'.$class . '.php';
В автозагрузчике нужен if (file_exists(..)), я по моему об этом уже писал.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L19
> $student = $db->isPswrdInDB($password)[0];
Надо во-первых, переименовать эту функцию (так как функции is... возвраают true/false а не массив), во-вторых сделать чтобы она сразу возвращала объект и [0] был не нужен.
> https://github.com/Si0n/register3/blob/master/lib/StudentsMapper.php#L68
> $stud = $srchStudents->fetchAll();
> $count = count($stud);
Вот это вообще неправильно, ты выкачиваешь всех студентов из базы в PHP только чтобы посчитать их количество и выбросить данные. Надо использовать SELECT COUNT(x) для таких случаев.
Если ты плохо знаешь SQL, у нас в ОП посте есть задания по нему, и там по моему есть ссылка на туториал.
> https://github.com/Si0n/register3/blob/master/lib/Student.php#L97
> $code = sha1($code);
Зачем нужна эта строчка? Или объясни, что она делает или давай ее удалим.
Когда ты будешь проверять имена и фамилии, помни что в России фамилия может содержать дефис, апостроф и состоять из нескольких слов: О'Генри, Сан Антуан Кристоф, Римский-Корсаков. Существуют фамилии из одной буквы, например китайская «Ю».
Хочешь проверять адрес email с помощью регулярных выражений? Прочти статьи: http://habrahabr.ru/post/55820/, http://habrahabr.ru/post/175375/
Теперь перейдем к HTML и интерфейсу.
- Подсказки надо делать через атрибут placeholder
- Вкладки сверху (регистрация и список студентов) не везде выводятся и активная вкладка никак не выделяется
- При клике по слову «Приезжий» в кружочке не появляется точечка, а должна появляться. Почитай про HTML тег label: http://htmlbook.ru/html/label
Тебе надо засунуть input и подпись к нему в label.
- Аналогично, подписи полей должны быть сделаны тегом label, чтобы при клике по ним курсор ставился в поле. Тег label специально придуман для подписей к полям.
- сама форма вся перекошена и подписи к полям больше самих полей.
Я тебе советую взять за основу код отсюда: http://getbootstrap.com/css/#forms и адаптировать его для твоей формы (например Horizontal form может тебе подойти)
- основную кнопку «Отправить данные» стоит сделать синим цветом и обычно ее располагают справа. Также, стоит переименовать ее в «Зарегистрироваться» («Сохранить» при редактировании)
- Функция «Посмотреть мои данные» /index.php?page=inspect у меня показывает пустые значения. Форма редактирования тоже.
Кстати, если ты хочешь лучше изучить HTML/CSS, у нас есть неплохие задания по ним в ОП-посте.
По этому файлу: https://github.com/V3N0m21/StudentList/blob/master/textAreaTest.php
Данные из ссылки не экранируются. Это значит что злоумышленник может с помощью ссылки вставить любой тег на страницу, это уязвимость XSS. Пример ссылки:
/1.php?text=<s>test
Она выведет зачеркнутое слово test, а должна вывести тег как есть.
Мой урок про XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md
Я переименовываю загруженные пользователями файлы в целях безопасности.
А как их отдать под оригинальным именем (сохраненным в базе)?
И я так и не понял, как же обезопаситься от загрузки хакерского скрипта.
htaccess только для апача, плюс провайдеры могут запретить php_flag engine 0
Мы с опом вроде бы решили, что лучше всего просто переименовать файл, чтобы хакер не знал, как его вызвать.
Но из-за нелюбви опа к хешам в именах возникает опасение, что умный хакир таки вычислит свой файл, если к его имени тупо конкатенировать айди или дату.
Я наверное пока так и оставлю, все равно потом придем к тому, что файлы нужно хранить в блоб-полях в базе.
Хотя наверное не каждый может себе позволить такую базу на не_представляю_сколько терабайт.
С mime-типами хочется разобраться. Я не понимаю, есть вообще какой-то четкий стандарт? Почему в разных источниках пишут разные типы?
В случае с php, на википедии говорится, что он обозначается text/php.
https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_MIME-%D1%82%D0%B8%D0%BF%D0%BE%D0%B2
application/x-httpd-php
http://webremeslo.ru/spravka/spravka3.html
Создал обычный hello.php с текстом
$finfo = new finfo(FILEINFO_MIME_TYPE);
echo $finfo->file('index.php');
Выдало text/x-php
Я как бы собираюсь строки на равенство === проверять. Как быть?
Переименовывать я предлагал с другой целью — если ты переименуешь файл в 1.txt то он не будет воспринят как php файл и выполнен сервером (а также не будет воспринят как htaccess). И пусть хакер сколько угодно раз его вызывает.
А, расширение менять.
Меня сбило с толку, что mime-тип продолжает возвращать text-x-php, даже если переименовать файл в hello.world
Хотя да, теперь апач при обращении к этому файлу отдает его простым текстом, не исполняет.
Bad Gateway - абулик, ну сколько можно?
Переименовывать я предлагал с другой целью — если ты переименуешь файл в 1.txt то он не будет воспринят как php файл и выполнен сервером (а также не будет воспринят как htaccess). И пусть хакер сколько угодно раз его вызывает.
> файлы нужно хранить в блоб-полях в базе.
Это неэффективно так как файлы с диска можно отдавать легким и быстрым nginx напрямую (или апачем без обращения к PHP), а из базы напрямую нельзя, только через запуск PHP скрипта, который тратит память и CPU и не умеет эффективно отдавать большие файлы. И сам подумай, если у тебя допустим люди качают 10 мегабайт файлов в секунду то ты этим автоматически к нагрузке на базу добавляешь эти 10 мегабайт в секунду.
Более того, если файл весит 1 гигабайт ты этот гигабайт должен загрузить в память базы, потом в память PHP скрипта и отдавать. А если 20 человек одновременно этот файл качает? Уже 20 + 20 гигабайт зря уходит. А нгинкс отдает напрямую с диска тратя может несколько мегабайт.
В общем, раздавать файлы эффективнее всего не обращаясь к PHP. PHP только для динамических страниц.
https://gist.github.com/codedokode/9424217
>нужно хранить данные в базе данных — ну я надеюсь, к этому моменту ты это осилишь
>Это неэффективно
Что ты меня путаешь, как путана.
майм-типы регистрирует IANA, вот официальный список: http://www.iana.org/assignments/media-types/media-types.xhtml
vnd. в имени типа значит что этот тип не универсальный, а это тип файла от какой-то программы (например документ Word)
x- обозначает не зарегистрированные официально типы
Как ты видишь, каждый официальный тип подкреплен RFC в котором он описан.
Для PHP официального типа нет, потому там должно быть что-то с x- в имени, и каждый может его обозначать как хочет.
> на википедии говорится, что он обозначается text/php.
Значит они считают его текстом
> application/x-httpd-php
А Апач — программой.
mime-тип определяется по содержимому. Я не уверен как вообще можно определить что файл является php-файлом. По <?php ? Ну так это может быть текстовый файл содержащий пример программы.
Определение типа имеет смысл для бинарных файлов у которых предусмотрен определенный формат данных, картинки, аудио, видеофайлы.
Под данными подразумеваются не файлы, а различная информация, которая используется на сайте. Инфа о пользователях, комментарии и прочее.
> Я как бы собираюсь строки на равенство === проверять. Как быть?
Если ты делаешь это для защиты от хакеров то не стоит так делать. Ведь легко взять картинку, засунуть в поле комментария (в некоторых картинках предусмотрено текстовое поле для комментария которое хранится где-то в середине файла) PHP код:
... данные картинки ...
<?php ... ?>
... данные картинки ...
Определяться она будет как картинка, так как у нее заголовок картинки, но если дать ей расширение PHP и вызвать, то код выполнится потому что PHP выполняет то что внутри <?php, а все остальное просто выводит.
finfo не может точно определить является файл php-кодом или нет, она лишь делает догадку, посмотрев на заголовок файла и поискав там типичные для разных типов файлов паттерны. Более того, в некоторых случаях тип файла достоверно вообще определить невозможно. Она может ошибаться и ее легко обмануть. Ты не должен использовать ее результаты в коде связанном с безопасностью.
Если ты делаешь это для вывода информации о файле, то просто заложи в проверку возможные варианты.
> Как отдавать файлы с сервера под другим именем?
Скачивать файлы через PHP довольно неэффективно — Апач, а тем более nginx делают это с затратой горазло меньших ресурсов и могут выдержать гораздо больше пользователей (а ведь на файлообменнике скачивание это основная функция).
Есть такие варианты:
— настроить переписывание в htaccess так, чтобы при обращении по URL /download/realname-1234/желаемое-имя.txt отдавался бы файл /upload/realname-1234 (при этом браузер пользователя берет имя файла из последнего сегмента URL)
Статья: http://habrahabr.ru/company/sprinthost/blog/129560/ + есть официальная дока на сайте Апача на английском
Подход с htaccess работает только в Апаче. Для nginx придется написать отдельное правило с регулярным выражением. Зато в скачивании никак не участвует PHP.
— использовать специальный заголовок X-SendFile. В этом случае при попытке скачивания PHP скрипт отдает вместо файла этот заголовок и завершается, а веб-сервер перхватывает его и отдает реальный файл. Такой подход позволяет PHP скрипту только инициировать скачивание и может использоваться для ограничения доступа, защиты от прямого скачивания, учета числа скачиваний, и т.д. Инфа: http://habrahabr.ru/post/151795/
Для nginx используется аналогичный подход, только заголовок называется по другому, X-Accel-Redirect. Чтобы это работало, надо установить в Апач/nginx соотв. модуль.
Нет, я выбираю html-шаблон для отображения страницы с подробным описанием файла в зависимости от его типа.
Если это картинка, в шаблоне будет тег <img> для превью, если видео, то нужен плеер.
Вот я и опасаюсь, что пропишу список форматов массивом, а потом окажется, что мне вернется не image/jpeg, как я ожидаю, а какая-то хрень типа image/x-jpeg, или что-то подобное.
Кстати, планирую в базе хранить mime, размер файла, а также поле, где в сериализованном виде будет массив спец-параметров, характерных для конкретного типа. Для image/* это будет array('resolution'=>array('width'=>640, 'height'=>480),)
для видео какой-нибудь кодек и т.д.
Одобряешь?
>>497064
Я не понял ничего.
>настроить переписывание в htaccess так, чтобы при обращении по URL /download/realname-1234/желаемое-имя.txt отдавался бы файл /upload/realname-1234
Мне по два файла что ли хранить? Какой в этом смысл? Нет, ты имел в виду что-то другое.
Вместо сериализации лучше JSON:
1) формат сериализации не документирован и может меняться между версиями php
2) JSON данные можно раскодировать любым другим языком, например яваскриптом, Руби, Скалой.
3) некоторые базы данных (Postgres) умеют работать с JSON, а для новой MySQL пилят функции:
http://blog.ulf-wendel.de/2013/mysql-5-7-sql-functions-for-json-udf/
http://2014.devconf.ru/data/2014/presentation/6.pdf
> Я не понял ничего.
>>настроить переписывание в htaccess так, чтобы при обращении по URL /download/realname-1234/желаемое-имя.txt отдавался бы файл /upload/realname-1234
> Мне по два файла что ли хранить? Какой в этом смысл?
Ты хранишь файл под именем /upload/realname-1234 но отдаешь по ссылке /download/realname-1234/желаемое-имя.txt (по этой ссылке файла нет разумеется, это работает переписывание через mod_rewrite) так как браузер берет имя файла из последнего сегмента URL и с такой ссылкой он сохранит файл под нужным нам именем.
Чтобы для видео выдавала скажем fps, для аудио какой-нибудь битрейт, для текстовых - кодировку например, для картинки разрешение и глубина цвета.
Пресловутую Id3 смотрел, ничего не понял. http://php.net/manual/ru/book.id3.php
Посему вопросы.
1. Эта библиотека только для аудио?
2. Нужно ли плясать с бубном, чтобы ее установить, или только раскомментировать экстеншн?
3. Чо она вообще может?
id3_get_frame_long_name — Возвращает длинное имя ID3v2 кадра
Какого нафиг кадра? Что за длинное имя? Что такое ID3v2?
id3_get_genre_id — Возвращает идентификатор жанра
Что за жанр? Что за галиматья?
Я хочу узнать простые характеристики файла, а они мне опять ссут в глаза какой-то чепухой.
Ладно, буду собирать на помойке левые функции. Для получения разрешения картинки сойдет getimagesize, mime-тип возвращает объект finfo.
И так далее, буду гуглить, что поделать.
Ок, json так json.
Правда я его не знаю, но видимо пришел его час.
>браузер берет имя файла из последнего сегмента URL и сохраняет файл под этим именем.
Вот оно что. Хорошо, хоть здесь все просто.
А не проще ли просто регулярками разрешения файлов чекать? Форматов медиа не так много, так что не думаю, что слишком гемморно будет.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L27
> $validation->validate($student, $data);
Если классу валидации нужен DataMapper, лучше передать его через конструктор. Это называется Dependency Injection и описано тут: https://gist.github.com/codedokode/e1d31a31b37d5f635057
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L39
> isset($student->password)
В чем смысл этой проверки? Поле всегда есть у объекта. Если ты хотел проверить что код не пуст, лучше использовать !empty()
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L4
> #if (file_exists($path)) {
Это надо исправить и раскомментировать
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L13
> if ($conn->connect_error) die ($conn->connect_error);
При ошибке лучше выбрасывать исключение так как оно идет в логи и можно отключить его вывод. Урок по исключениям: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L13
> $this->currentItem = 0;
> $this->start = 0;
Эти поля почему-то не зависят от номера страницы. Если они используются, надо исправить, если нет то удалить их.
> $this->pages = ceil($this->rows/$this->itemsPerPage);
Это логичнее перенести в конструктор, а то у тебя поле pages не всегда отражает актуальную информацию, а это плохо.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L26
> if (!empty($numbers)) {
> return $numbers;
> } else {return null;}
Вместо null лучше вернуть пустой массив чтобы результат функции был одного типа.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L53
> $link .= "&search=" . h($search);
При подстановке данных в ссылку надо кодировать их через urlencode (а через htmlspecialchars очевидно не надо, это же ссылка, а не HTML). Также, ссылку удобно собирать через http_build_query.
> &
А вот это лучше делать в шаблоне при выводе с помощью h($link), а в самой ссылке использовать просто &
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L32
> public function getAttributes()
Зачем эта функция? Я не представляю как запомнить под каким номером там что идет в массиве.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L34
> if (count($this->errors) !== 0) {
> return 1;
> } else { return 0;}
Что за странное оофрмление if/else? делай по стандарту: http://www.php-fig.org/psr/psr-2/ru/#1.1.-Пример
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L12
> ?sort=name<?php if($sort =='name' && $dir =='desc') echo '&dir=asc'; ?>&search=<?php echo u($search)?>
Это тяжело читать и надо вынести в функцию. Не забудь обработать подставляемые в ссылку данные через urlencode, а выводимые на странице через h()
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L4
> Имя:<br> <input type="text" name="Name" value="<?=htmlspecialchars($student->name);?>">
Подписи к элементам формы оформляются тегом label
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L43
> $email = $this->db->real_escape_string($email);
При использовании плейсхолдеров это делать не надо
Ссылка на CSS файл в шаблоне неправильная.
- Вместо «L/N» лучше бы выводить в таблице слово. Ты можешь сделать функцию или метод у студента для этого.
- При сортировке по колонке хорошо бы рядом с ней выводить стрелочку или треугольник (символы: http://unicode-table.com/ru/sets/arrows-symbols/ )
- при поиске стоит подставлять введенное слов в поле поиска, а также выводить текст:
«Показаны только студенты, найденные по слову XXX. Показать все записи.»
- при клике по словам вроде «мужской», точка не ставится. Используй label чтобы это исправить
- раз уж ты используешь бутстрап, попробуй сверстать форму как описано в документации: http://getbootstrap.com/css/#forms
- на странице не хватает полей, она почему-то вжата прямо в края. Наверно проще всего решить это засунув содержимое в .container-fluid и .row
- чтобы пометить ошибочное поле, есть такой класс: http://getbootstrap.com/css/#forms-control-validation (заметь там есть красивый вариант с иконкой)
- для кнопки лучше взять синюю primary: http://getbootstrap.com/css/#buttons-options
- для надписи об ошибке можно использовать этот класс: http://getbootstrap.com/css/#helper-classes-colors
- для меню с формой поиска это: http://getbootstrap.com/components/#navbar
- в общем, потрать полчасика на пролистывание документации по бутстрапу и ознакомься, что там есть. Обрати внимание что там идет в комплекте шрифт векторных иконок которые тоже могут быть полезны: http://getbootstrap.com/components/ (русский перевод не знаю насколько точен и актуален: http://bootstrap-3.ru/css.php )
- для данных из формы надо делать trim() а то ввел пробел после года и все, ошибка
- Поиск по именам у тебя чувствителен к регистру и это плохо. Надо исправить. Чувствительность к регистру (а также правила сортировки) задается на уровне базы, таблицы, колонки, с помощью collation:
http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
Обрати внимание кстати, что сортировка в разных языках идет по разным правилам (например в некоторых европейских языках буквы с точечками идут рядом с обычными, в некоторых в конце алфавита) и потому только кодировки для правильной сортировки мало.
> CHARACTER SET utf8 COLLATE utf8_general_ci;
значит независимо от регистра (ci = case insensitive)
> COLLATE utf8_bin
значит зависимо от регистра
У тебя в SQL collate не прописан (как и кодировка что плохо) и потому видимо применяются какие-то настройки по умолчанию которые у меня задают поиск с чувствительностью к регистру.
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L27
> $validation->validate($student, $data);
Если классу валидации нужен DataMapper, лучше передать его через конструктор. Это называется Dependency Injection и описано тут: https://gist.github.com/codedokode/e1d31a31b37d5f635057
> https://github.com/V3N0m21/StudentList/blob/master/profile.php#L39
> isset($student->password)
В чем смысл этой проверки? Поле всегда есть у объекта. Если ты хотел проверить что код не пуст, лучше использовать !empty()
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L4
> #if (file_exists($path)) {
Это надо исправить и раскомментировать
> https://github.com/V3N0m21/StudentList/blob/master/lib/init.php#L13
> if ($conn->connect_error) die ($conn->connect_error);
При ошибке лучше выбрасывать исключение так как оно идет в логи и можно отключить его вывод. Урок по исключениям: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L13
> $this->currentItem = 0;
> $this->start = 0;
Эти поля почему-то не зависят от номера страницы. Если они используются, надо исправить, если нет то удалить их.
> $this->pages = ceil($this->rows/$this->itemsPerPage);
Это логичнее перенести в конструктор, а то у тебя поле pages не всегда отражает актуальную информацию, а это плохо.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L26
> if (!empty($numbers)) {
> return $numbers;
> } else {return null;}
Вместо null лучше вернуть пустой массив чтобы результат функции был одного типа.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Paginator.php#L53
> $link .= "&search=" . h($search);
При подстановке данных в ссылку надо кодировать их через urlencode (а через htmlspecialchars очевидно не надо, это же ссылка, а не HTML). Также, ссылку удобно собирать через http_build_query.
> &
А вот это лучше делать в шаблоне при выводе с помощью h($link), а в самой ссылке использовать просто &
> https://github.com/V3N0m21/StudentList/blob/master/lib/Student.php#L32
> public function getAttributes()
Зачем эта функция? Я не представляю как запомнить под каким номером там что идет в массиве.
> https://github.com/V3N0m21/StudentList/blob/master/lib/Validation.php#L34
> if (count($this->errors) !== 0) {
> return 1;
> } else { return 0;}
Что за странное оофрмление if/else? делай по стандарту: http://www.php-fig.org/psr/psr-2/ru/#1.1.-Пример
> https://github.com/V3N0m21/StudentList/blob/master/views/list.php#L12
> ?sort=name<?php if($sort =='name' && $dir =='desc') echo '&dir=asc'; ?>&search=<?php echo u($search)?>
Это тяжело читать и надо вынести в функцию. Не забудь обработать подставляемые в ссылку данные через urlencode, а выводимые на странице через h()
> https://github.com/V3N0m21/StudentList/blob/master/views/reg.php#L4
> Имя:<br> <input type="text" name="Name" value="<?=htmlspecialchars($student->name);?>">
Подписи к элементам формы оформляются тегом label
> https://github.com/V3N0m21/StudentList/blob/master/lib/StudentMapper.php#L43
> $email = $this->db->real_escape_string($email);
При использовании плейсхолдеров это делать не надо
Ссылка на CSS файл в шаблоне неправильная.
- Вместо «L/N» лучше бы выводить в таблице слово. Ты можешь сделать функцию или метод у студента для этого.
- При сортировке по колонке хорошо бы рядом с ней выводить стрелочку или треугольник (символы: http://unicode-table.com/ru/sets/arrows-symbols/ )
- при поиске стоит подставлять введенное слов в поле поиска, а также выводить текст:
«Показаны только студенты, найденные по слову XXX. Показать все записи.»
- при клике по словам вроде «мужской», точка не ставится. Используй label чтобы это исправить
- раз уж ты используешь бутстрап, попробуй сверстать форму как описано в документации: http://getbootstrap.com/css/#forms
- на странице не хватает полей, она почему-то вжата прямо в края. Наверно проще всего решить это засунув содержимое в .container-fluid и .row
- чтобы пометить ошибочное поле, есть такой класс: http://getbootstrap.com/css/#forms-control-validation (заметь там есть красивый вариант с иконкой)
- для кнопки лучше взять синюю primary: http://getbootstrap.com/css/#buttons-options
- для надписи об ошибке можно использовать этот класс: http://getbootstrap.com/css/#helper-classes-colors
- для меню с формой поиска это: http://getbootstrap.com/components/#navbar
- в общем, потрать полчасика на пролистывание документации по бутстрапу и ознакомься, что там есть. Обрати внимание что там идет в комплекте шрифт векторных иконок которые тоже могут быть полезны: http://getbootstrap.com/components/ (русский перевод не знаю насколько точен и актуален: http://bootstrap-3.ru/css.php )
- для данных из формы надо делать trim() а то ввел пробел после года и все, ошибка
- Поиск по именам у тебя чувствителен к регистру и это плохо. Надо исправить. Чувствительность к регистру (а также правила сортировки) задается на уровне базы, таблицы, колонки, с помощью collation:
http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
Обрати внимание кстати, что сортировка в разных языках идет по разным правилам (например в некоторых европейских языках буквы с точечками идут рядом с обычными, в некоторых в конце алфавита) и потому только кодировки для правильной сортировки мало.
> CHARACTER SET utf8 COLLATE utf8_general_ci;
значит независимо от регистра (ci = case insensitive)
> COLLATE utf8_bin
значит зависимо от регистра
У тебя в SQL collate не прописан (как и кодировка что плохо) и потому видимо применяются какие-то настройки по умолчанию которые у меня задают поиск с чувствительностью к регистру.
https://github.com/tokotun/JS/blob/master/lesson_13.html
https://github.com/tokotun/JS/blob/master/lesson_13.js
https://github.com/tokotun/JS/blob/master/lesson_13.js#L166
Как создать объект имея имя класса в переменной? Сделав как то так.
var element = new className(arr);
В место того что бы плодить условия. Через switch.
https://github.com/tokotun/JS/blob/master/lesson_13.js#L91
> this._power = power;
>В качестве упражнения было бы полезно вместо этого вызвать метод предка ElementGrid.setPower
У меня заработало только так: ElementGrid.prototype.setPower.call(this, power);
Для медиафайлов лучший вариант это getId3: https://github.com/JamesHeinrich/getID3/
демо: http://www.getid3.org/demo/
ставится через композер.
> Эта библиотека только для аудио?
Твоя только для форматов файлов с id3 тегами (по моему это только mp3), в то время как другие звуковые форматы используют другие способы.
Вики: https://ru.wikipedia.org/wiki/ID3_(%D0%BC%D0%B5%D1%82%D0%B0%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5)
> Какого нафиг кадра?
Очевидно кадр это блок в файле с данными id3
> Что такое ID3v2?
Вторая версия id3, смотри вики. По моему она отличается от первой поддержкой utf8 и еще чем-то.
> Что за жанр? Что за галиматья?
В id3 теги в mp3 файле можно записать id жанра к которому относится трек. Список
http://www.linuxselfhelp.com/HOWTO/MP3-HOWTO-13.html#ss13.3
> Я хочу узнать простые характеристики файла, а они мне опять ссут в глаза какой-то чепухой.
Очевидно предполагается что ты хотя бы в википедии прочитаешь про id3 прежде чем использовать библиотеку чтения id3 тегов. Ну и как я написал выше, есть более удобная getId3
Для медиафайлов лучший вариант это getId3: https://github.com/JamesHeinrich/getID3/
демо: http://www.getid3.org/demo/
ставится через композер.
> Эта библиотека только для аудио?
Твоя только для форматов файлов с id3 тегами (по моему это только mp3), в то время как другие звуковые форматы используют другие способы.
Вики: https://ru.wikipedia.org/wiki/ID3_(%D0%BC%D0%B5%D1%82%D0%B0%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5)
> Какого нафиг кадра?
Очевидно кадр это блок в файле с данными id3
> Что такое ID3v2?
Вторая версия id3, смотри вики. По моему она отличается от первой поддержкой utf8 и еще чем-то.
> Что за жанр? Что за галиматья?
В id3 теги в mp3 файле можно записать id жанра к которому относится трек. Список
http://www.linuxselfhelp.com/HOWTO/MP3-HOWTO-13.html#ss13.3
> Я хочу узнать простые характеристики файла, а они мне опять ссут в глаза какой-то чепухой.
Очевидно предполагается что ты хотя бы в википедии прочитаешь про id3 прежде чем использовать библиотеку чтения id3 тегов. Ну и как я написал выше, есть более удобная getId3
А как? Если ты будешь запрещать расширения из списка то есть шанс что ты забудешь какое-то расширение которое апач вопринимает как php (вроде shtml, phtml или php5). Да и непонятно тогда как через файлообменник поделиться php скриптом. Я считаю надо поддерживать любые файлы (разве что кроме исполняемых чтобы вирусы не распространять).
> Эта библиотека только для аудио?
Да, причем только для Mp3
> 2. Нужно ли плясать с бубном, чтобы ее установить, или только раскомментировать экстеншн?
Открываешь специальный раздел мануала и читаешь: http://php.net/manual/ru/id3.installation.php
> DLL для этого расширения PECL в данный момент недоступна.
Зайдем на pecl http://pecl.php.net/package/id3 и действительно, dll нет, только исходники.
Значит под винду единственный вариант скачать исходники библиотеки, скачать исходники php, установить компилятор (по моему visual studio express, тяжелый) и компилировать.
Под линуксом проще, там достаточно команды pecl install id3. Под виндоус не уверен, есть ли такая возможнсть.
> 3. Чо она вообще может?
Очевидно читать содердимое id3 тегов из mp3 файлов.
Ну так не надо забывать. А вообще я имел ввиду использовать регулярки для проверки, типа если кончается на jpg, png, gif и пр., то картинка и соответственно ее вывести надо в тегах <img>. Тоже самое с остальными разрешениями, которые нужно будет как-то особо обработать. А все остальные файлы, которые не проходят проверку регуляркой выводить как обычно.
Можно по расширению, можно по mime типу. В случае срасширением будь готов что файл может оказаться на самом деле с другим форматом.
> Ну так не надо забывать.
А списка никакого нет. Хостеры сами добавляют дополнительные типы вроде php4 в конфиг Апача. Потому идея создания черного списка заведомо плохая, можно использовать белый список (запрещено все что не разрешено) но это неудобства для пользователей. Более того, если ты разрешишь rar а апач о нем не знает то файл
troll.php.rar
будет воспринят апачом как php файл.
>>497125
Суть в том, что я мне грустно опять перечитывать сотни страниц, чтобы в итоге получить искомые две-три функции.
Жопой чую, что там все элементарно, скажем:
$id3 = new Id3('file.name');
$id3->size;
$id3->duration;
$id3->format;
$id3->bitrait;
Ну дал ты мне ссылку на гитхаб. Мне перечитывать весь исходный код в надежде найти эти три метода или свойства?
Ну что ж, в добрый путь. Через неделю увлекательного чтения вернусь.
Ну это уже не твои проблемы. Твоя задача принять файл и разместить его на хостинге. А что там в нем содержится - не так важно. Главное, чтобы сайт не распидорасило от вредоносных скриптов.
>>497134
>troll.php.rar будет воспринят апачом как php файл.
Что, серьезно? Пиздец. Не знал. И что с этим делать?
> Как создать объект имея имя класса в переменной?
В JS нельзя никак, но можно сделать словарь вида название -> функция-конструктор:
var classes = {
PowerHouse: PowerHouse,
...
};
Алсо в твоем случае вместо имени класса в фабрику логичнее сразу передавать функцию-конструктор. Мысли как яваскриптщик, а не как php-ник.
После if лучше всегда ставить {} даже если там одно действие. Это делает код надежнее и другому человеку не придется ставить скобки за тебя когда он захочет дописать второе действие (ну и можно просто забыть про них).
Ну и читать это трудно так как тут вообще с первого взгляда непонятно что внутри if а что нет:
> if (trade == 'sell') arr.sort(
>function (a, b) {
> return b.getPrice() - a.getPrice();
> });
Ужасно же.
> 'продано '+tradePower+' энергии. Получено '+money+' денег.';
Лучше возвращать информаию не строкой, а например словарем с числами, а уже тот кто вызвал функцию что хочет то и делает.
> if (trade == 'sell')
> if (trade == 'buy')
надо выбрасывать исключение если передано ни то ни другое. Ну и для 2 вариантов наверно проще использовать true/false.
> EGrid.prototype.tradeEnergy = function(power, trade){
Эта функция большая и сложная. Чтобы ее было легче воспринимать, вынеси отдельные действия в отдельные методы, а именно:
— поиск всех подходящих нам линий
>var power = Math.abs(power);
аргументы не надо объявлять как переменные
> function(timeOfDay = 'day'){
ты уверен что это везде работает? По моему такая вещь доступна только в Es6 и не везде.
Алсо, проверь-ка еще свой код тут http://jshint.com/
Там есть еще более новая версия jslint, но что-то он странные сообщения выдает.
Кстати, jslint можно установить как плагин к редактору, например sublime и автоматически проверять код при сохранении.
> function PowerLine(obj) {
> this.setPowerLine(obj.power, obj.price);
Это бессмысленное усложнение, выгоднее сделать 2 аргумента у конструктора чем вводить лишний объект
> var POWERHOUSE = 'Powerhouse';
Если ты сделал константу, то везде ее и используй, а то тут строка вместо константы:
> case 'Powerhouse':
Это ведет к ошибкам и путанице
> У меня заработало только так: ElementGrid.prototype.setPower.call(this, power);
Так и надо.
> Как создать объект имея имя класса в переменной?
В JS нельзя никак, но можно сделать словарь вида название -> функция-конструктор:
var classes = {
PowerHouse: PowerHouse,
...
};
Алсо в твоем случае вместо имени класса в фабрику логичнее сразу передавать функцию-конструктор. Мысли как яваскриптщик, а не как php-ник.
После if лучше всегда ставить {} даже если там одно действие. Это делает код надежнее и другому человеку не придется ставить скобки за тебя когда он захочет дописать второе действие (ну и можно просто забыть про них).
Ну и читать это трудно так как тут вообще с первого взгляда непонятно что внутри if а что нет:
> if (trade == 'sell') arr.sort(
>function (a, b) {
> return b.getPrice() - a.getPrice();
> });
Ужасно же.
> 'продано '+tradePower+' энергии. Получено '+money+' денег.';
Лучше возвращать информаию не строкой, а например словарем с числами, а уже тот кто вызвал функцию что хочет то и делает.
> if (trade == 'sell')
> if (trade == 'buy')
надо выбрасывать исключение если передано ни то ни другое. Ну и для 2 вариантов наверно проще использовать true/false.
> EGrid.prototype.tradeEnergy = function(power, trade){
Эта функция большая и сложная. Чтобы ее было легче воспринимать, вынеси отдельные действия в отдельные методы, а именно:
— поиск всех подходящих нам линий
>var power = Math.abs(power);
аргументы не надо объявлять как переменные
> function(timeOfDay = 'day'){
ты уверен что это везде работает? По моему такая вещь доступна только в Es6 и не везде.
Алсо, проверь-ка еще свой код тут http://jshint.com/
Там есть еще более новая версия jslint, но что-то он странные сообщения выдает.
Кстати, jslint можно установить как плагин к редактору, например sublime и автоматически проверять код при сохранении.
> function PowerLine(obj) {
> this.setPowerLine(obj.power, obj.price);
Это бессмысленное усложнение, выгоднее сделать 2 аргумента у конструктора чем вводить лишний объект
> var POWERHOUSE = 'Powerhouse';
Если ты сделал константу, то везде ее и используй, а то тут строка вместо константы:
> case 'Powerhouse':
Это ведет к ошибкам и путанице
> У меня заработало только так: ElementGrid.prototype.setPower.call(this, power);
Так и надо.
Не, вроде все не так ужасно.
Полистал код демок, делается как-то так:
$getID3 = new getID3;
// ...
$ThisFileInfo = $getID3->analyze($FullFileName);
// ...
echo $ThisFileInfo['comments_html']['artist'];
echo $ThisFileInfo['audio']['bitrate'];
echo $ThisFileInfo['playtime_string'];
...
там есть папка с примерами кода. Посмотри их.
>>497144
> А что там в нем содержится - не так важно.
Если ты попытаешься вызвать imagefromjpeg то важно.
> И что с этим делать?
превозмогать. Это фича Апача Content Negotiation, он отбрасывает непонятные расширения и ищет подходящий контент под запрос, например чтобы показать страницу на нужном языке:
http://httpd.apache.org/docs/current/content-negotiation.html (англ)
http://blog.sjinks.pro/administering/901-mod_rewrite-content-negotiation/
http://itbuben.org/blog/Unix-way/1423.html
Впрочем все зависит от того каким способом подключен php, там ест 2 способа, с одним (который черз типы) работает, с другим (который через регулярку) нет.
Если так:
<FilesMatch \.php$>
SetHandler application/x-httpd-php
то не сработает.
Если так:
AddType application/x-httpd-php .php
то сработает.
там есть папка с примерами кода. Посмотри их.
>>497144
> А что там в нем содержится - не так важно.
Если ты попытаешься вызвать imagefromjpeg то важно.
> И что с этим делать?
превозмогать. Это фича Апача Content Negotiation, он отбрасывает непонятные расширения и ищет подходящий контент под запрос, например чтобы показать страницу на нужном языке:
http://httpd.apache.org/docs/current/content-negotiation.html (англ)
http://blog.sjinks.pro/administering/901-mod_rewrite-content-negotiation/
http://itbuben.org/blog/Unix-way/1423.html
Впрочем все зависит от того каким способом подключен php, там ест 2 способа, с одним (который черз типы) работает, с другим (который через регулярку) нет.
Если так:
<FilesMatch \.php$>
SetHandler application/x-httpd-php
то не сработает.
Если так:
AddType application/x-httpd-php .php
то сработает.
>- Функция «Посмотреть мои данные» /index.php?page=inspect у меня показывает пустые значения. Форма редактирования тоже
Эмм, не знаю, у меня если зайти без кук на сайт не доступна функция посмотреть мои данные, если с куками, то нормально достает студента из бд - пикрелейтед.
>- Вкладки сверху (регистрация и список студентов) не везде выводятся и активная вкладка никак не выделяется
Я хотел это сделать, я в гугле как минимум час провел пытаясь найти функции на js так как моих скудных знаний в js вряд ли бы хватило в написании таковой с нуля, да и в редактировании тех, что я нашел я не приуспел. А по другому я не знаю как изменить текущий класс элемента. Разве что через file get contents брать и регулярками изменять текст каждый раз.
Вроде бы там не нужен JS, надо просто класс добавить на активную вкладку (если ты используешь бутстрап).
http://getbootstrap.com/components/#nav-tabs
Я прописывал class="active" но сам по себе он не переключается при нажатии на другие вкладки, та на которую изначально прописан класс "active" остается ей даже если она не активна в данный момент. Нужно подключать функцию видимо или прописывать её
А тебе и не надо чтобы они переключались, у тебя ведь переход на другую страницу, а на другой странице можно другой таб сделать активным.
А так да, надо яваскрипт подключать чтобывкладки переключались без перезагрузки страницы.
У меня переход через инклуды прописан, шапка остается статической, а наполнение подгружается.
Ты что-то путаешь. Когда ты кликаешь по ссылке, вся страница перезагружается заново, включая шапку и меню. Браузер и Апач ничего не знают про твои инклуды и загружают страницу заново. Соответственно ты можешь сделать какую-то переменную, хранящую какую вкладку подсвечивать и добавлять класс в зависимости от ее значения.
> У меня переход через инклуды прописан,
переход делается у тебя кликом по ссылке и при этом страница загружается браузером с сервера целиком.
О, исходя из этого легко реализовал это и без js.
https://github.com/tokotun/JS/blob/master/lesson_13.js
> function PowerLine(obj) {
> this.setPowerLine(obj.power, obj.price);
>Это бессмысленное усложнение, выгоднее сделать 2 аргумента у конструктора чем вводить лишний объект
Теперь передаю в конструктор 2 переменные вместо обьекта. На фабрике сделал такое условие.
https://github.com/tokotun/JS/blob/master/lesson_13.js#L186
>Алсо, проверь-ка еще свой код тут http://jshint.com/
187 A constructor name should start with an uppercase letter.
189 A constructor name should start with an uppercase letter.
Но там просто переменная в которой находится конструктор. А переменные нужно писать с маленькой буквы.
Это предупреждение игнорировать?
https://github.com/tokotun/JS/blob/master/lesson_13.js#L77
Этот код читаем?
Опчег, скажи пару слов об xml: где применяется, в чем преимущество, что такое собственно xml-схема и полностью ли она заменяет dtd или дополняет ли его.
Я прочитал немного мутных статей шизоидов, не умеющих внятно излагать свои мысли и считающих быдлом тех, кому лень разбираться в их высерах, поковырял примеры.
Изложу здесь конспект того, что я вынес из всего этого. Поправь, если я что-то неверно понял.
XML - это язык разметки текстовых данных. Что такое разметка? Это назначение определенного логического или семантического смысла участкам данных.
В случае с html как разновидностью языка разметки, чтобы выделить определенным форматированием (цвет текста, отступы, шрифт) тот или иной участок текста на веб-странице, мы забираем этот фрагмент в html-теги, уже несущие в себе зашитое намертво описание. Тег <b> применяет к заключенному в него фрагменту текста жирное начертание, например. Хотя это описание элемента можно и переопределить через css-стили, все же принято этого не делать, поскольку теряется семантика.
Одним словом, html в первую очередь описывает внешний вид документа.
XML позволяет нам самим создавать элементы, путем описания тегов, их структуры вложенности, допустимых атрибутов, допустимого типа текстовых данных (например, мы можем создать тег <price>, внутри которого могут находиться только integer данные).
Сначала для этого описания использовался DTD, затем вроде бы на смену ему пришли xml-схемы. Они ссылаются на DTD от w3.org <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">, которого вроде бы достаточно для большинства случаев. Если нам понадобится намутить что-то свое, в принципе можно кроме этой схемы w3.org подключить и свой DTD в случае необходимости.
Применяется XML в случае, когда нужно передать большой фрагмент данных, и в этом потоке нужно естественно как-то обозначить, какие данные что обозначают.
Допустим, я хочу создать букинистический сайт, что-то вроде livelib или books.imhonet.ru , но базу книг брать неоткуда, да и не хочется ее содержать на своем сервере. Тогда можно получить этот контент в виде xml-документа, где соответствующими тегами обозначено, какой фрагмента текста отвечает за фамилию автора, какой за год издания, IBSN и так далее.
Я подозреваю, что большинство интернет-магазинов бытовой техники, электроники, чего угодно, имеют общую базу, из которой получают данные именно в виде xml.
--------------------------------------------------------------------------------
Нет ли у тебя каких-нибудь упражнений на эту тему?
Опчег, скажи пару слов об xml: где применяется, в чем преимущество, что такое собственно xml-схема и полностью ли она заменяет dtd или дополняет ли его.
Я прочитал немного мутных статей шизоидов, не умеющих внятно излагать свои мысли и считающих быдлом тех, кому лень разбираться в их высерах, поковырял примеры.
Изложу здесь конспект того, что я вынес из всего этого. Поправь, если я что-то неверно понял.
XML - это язык разметки текстовых данных. Что такое разметка? Это назначение определенного логического или семантического смысла участкам данных.
В случае с html как разновидностью языка разметки, чтобы выделить определенным форматированием (цвет текста, отступы, шрифт) тот или иной участок текста на веб-странице, мы забираем этот фрагмент в html-теги, уже несущие в себе зашитое намертво описание. Тег <b> применяет к заключенному в него фрагменту текста жирное начертание, например. Хотя это описание элемента можно и переопределить через css-стили, все же принято этого не делать, поскольку теряется семантика.
Одним словом, html в первую очередь описывает внешний вид документа.
XML позволяет нам самим создавать элементы, путем описания тегов, их структуры вложенности, допустимых атрибутов, допустимого типа текстовых данных (например, мы можем создать тег <price>, внутри которого могут находиться только integer данные).
Сначала для этого описания использовался DTD, затем вроде бы на смену ему пришли xml-схемы. Они ссылаются на DTD от w3.org <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">, которого вроде бы достаточно для большинства случаев. Если нам понадобится намутить что-то свое, в принципе можно кроме этой схемы w3.org подключить и свой DTD в случае необходимости.
Применяется XML в случае, когда нужно передать большой фрагмент данных, и в этом потоке нужно естественно как-то обозначить, какие данные что обозначают.
Допустим, я хочу создать букинистический сайт, что-то вроде livelib или books.imhonet.ru , но базу книг брать неоткуда, да и не хочется ее содержать на своем сервере. Тогда можно получить этот контент в виде xml-документа, где соответствующими тегами обозначено, какой фрагмента текста отвечает за фамилию автора, какой за год издания, IBSN и так далее.
Я подозреваю, что большинство интернет-магазинов бытовой техники, электроники, чего угодно, имеют общую базу, из которой получают данные именно в виде xml.
--------------------------------------------------------------------------------
Нет ли у тебя каких-нибудь упражнений на эту тему?
https://github.com/Si0n/register3
Оп жду твоих замечаний и наставлений.
Перекат в это тред?
>>494598
Вы видите копию треда, сохраненную 23 июня 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.