Вы видите копию треда, сохраненную 11 марта 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (необязательно).
Предыдущий тред был тут: >>431924
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП отвечает даже на самые нубские вопросы. ОП заходит где-то раз в день, не жди его, решай задачки дальше.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Учебник дает основы языка PHP, но чтобы делать сайты, этого недостаточно. Если ты его прошел, то надо переходить в более серьезным задачкам, которые научат тебя как выдавать страницы в браузер, работе с таблицами в БД, работе с формами, MVC.
- Простая, но полезная задача сделать список студентов: https://gist.github.com/codedokode/d7e7f11449fc3bcb24b4
- Более сложная задача сделать файлообменник на микрофреймворке 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:
Нужен ли ООП, фреймворки, 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
>уроков плавно подводящих к тому, как сделать задачи выше, пока нет
А когда будут? А то получается сначала синтаксис, а потом сразу ПАТТЕРНЫ ПАТТЕРНЫ ПРОЕКТИРОВАНИЕ ЗАПРОСЫ
Надеюсь, что позже сделаю, а пока что учимся путем проб и ошибок. Если ты сделал задание и у меня нет ни одного замечания, то ты выучил то, что требовалось. Ну и если ты будешь код показывать с самого начала, то я скажу что не так и тебе меньше исправлять придется чем если ты все по тихлому сделаешь и только в конце покажешь (на практике, процентов 50 в таком случае придется переделывать).
Куки — это данные, которые сервер может с помощью специального заголовка передать браузеру, тот их сохранит и будет в дальнейшем отправлять на серве с каждым запросом. То есть куки — это хранящиеся в браузере данные.
Для начала почитай это
https://ru.wikipedia.org/wiki/HTTP_cookie
http://citforum.ru/internet/html/cookie.shtml
В PHP чтобы выставить куки, есть функция:
http://php.net/manual/ru/function.setcookie.php
Переданные браузером куки PHP до запуска твоего скрипта автоматически разбирает и складывает в массив:
http://php.net/manual/ru/reserved.variables.cookies.php
В описании кук тебе могут встретиться понятия вроде «HTTP запрос», «HTTP заголовок». Если ты их не очень понимаешь, почитай про протокол HTTP. Это протокол (что-то вроде языка), на котором общаются браузер и веб-сервер: https://ru.wikipedia.org/wiki/HTTP
Протокол HTTP относительно прост. Браузер посылает запрос (например запрос на получение определенной страницы или скачивание файла), сервер обрабатывает его и возвращает ответ. И ответ, и запрос состоят из заглавной строки, заголовков и тела (необязательная часть).
что ты должен изучить:
- как работают куки
- свойства кук (path, domain, secure, httponly)
- ограничения по размеру хранимой информации и числу кук
- как из PHP выставить куку или прочесть присланные браузером куки
- как удалить куки из PHP
- как удалить куки в браузере
- как работают куки в приватном режиме браузера
В качестве мини-задачи на куки можешь сделать такое задание: сделай страницу, на которой выводится какой по счету раз ты на нее зашел. Число посещений должно храниться в куках, так что при заходе из другого браузера или из приватного режима оно считается с нуля.
Оп, не смотрел моё поделие?
https://github.com/d-beekeeper/ratchat
А то может я пропустил чего?
Сделал задачку с калькулятором, пока изи мод.
> - Простая, но полезная задача сделать список студентов
Вот в этой задаче index.php и edit.php в корневом, а еще файлы с классами, темплейты и css из бутсрапа их куда класть?
Может вопрос глупый, но меня немного стопорнул.
ага, временный каталог называй 1
каталог с настройками config
каталог с приватными данными репозитория .git
каталог с админкой admin, файл с паролями htpasswd
файл с паролями к базам данных - config.php.old или даже index.php.old
Почему не выставляются куки?
Cannot modify header information - headers already sent by
Где то до setcookie стоит echo или ещё что-то, отправляющее данные в браузер юзера. Как только данные начали уходить - заголовки тоже того...
Кстати банальные пара пробелов в самом конце файла, после закрывающего тега ?> - и пробелы, а с ними и заголовки, уходят в браузер. Поэтому, кстати, сегодня никто в PHP не-вьюхах файлах закрывающих тегов не ставит.
эх, тяжела жизнь пхппрогромиста
1) Чем чревато создание шаблонизатора таким образом, что он парсит содержимое файла, через
echo str_replace(array_keys(МАССИВ), array_values(МАССИВ), file_get_contents($this->path.ИМЯШАБЛОНА));
выводит пользователю на экран. Потеря в производительности? Другие подводные камни?
2) Структура проекта такова, что любой php-скрипт, на который осуществляется переход с передачей POST или GET, передает все параметры и производит вычисления через другой класс, запрашиваемый через require_once. То есть, какой бы не был php-скрипт, все вычисления, связь с базой данных, и прочее происходит через отдельный класс, и можно сделать так, что всё отображение производится через единственный index.php а все вычисления и связь с БД через core.php. Какие здесь подводные камни?
Спрашиваю, чтобы не наделать делов и потом переделывать весь проект в случае, если пойду по неверному пути.
На голом ПХП пишут только ньюфаги в этом ИТТ треде. А во всех фреймворках выходной поток перехватывается, и ничего лишнего никуда не уходит раньше времени.
>Чем чревато создание шаблонизатора
> всё отображение производится через единственный index.php а все вычисления и связь с БД через core.php
Ты щас занимаешься тем, что изобретаешь собственный фреймворк. В первом случае ты делаешь тормознутое говно, а во втором - к твоей чести - ты все делаешь правильно. Ещё чуть чуть и до MVC самостоятельно додумаешься.
Не страдай фигней. Возьми микрофреймворк какой нибудь, типа Slim - там всё это уже изобретено для тебя куда более опытными дядьками. Если очень интересно - как это правильно делать - можешь исходники того же Слима почитать.
А насколько тормознутое? Например, при 100 пользователях онлайн на каком-нибудь типичном недорогом хостинге будет ли задержка заметна. Не хотел вставлять php-код в html-шаблоны из-за безопасности, вдруг кто-то сможет каким-то образом включить свой код и творить всё что угодно.
Ну а про MVC я читал уже, поэтому старался все компоненты изолировать друг от друга.
>е хотел вставлять php-код в html-шаблоны из-за безопасности
какие то у тебя страные соображения о безопасности. как может повредить строка в шаблоне вида <?php echo $someVariable ?>
если в $somevariable строка вида '<?php makeEvilThing(); ?>' ??
Она же ни при каких услдовиях не исполнится (если только ты её в eval() не передашь, но про этот оператор забудь, он не для нубов)
А вообще это называется "слышал звон, да не знаю где он". Прямая вставка пришедших от пользователя данных в шаблон - действительно жопа. Но совсем по другой причине. Читай:
https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3
Потому что ob_end_clean просто очищает буфер. Удаляет всё, что нарендерено. Но тебе же с ним что то сделать надо? Например echo ($renderer->render(['a'=> 'somestring]))
Бля, опять я их перепутал. Спасибо.
Сайт и бд в utf-8 кодировке. Читаю текстовый файл.
Файл в кодировке win-1251. И конечно же русский текст становится кракозябрами на php странице (чья кодировка utf-8) и не заносится в БД (где тоже все записи в utf-8)
Вопрос, как не трогая кодировку текстового файла (он должен быть в win-1251 - он генерируется одной програмулиной) и тем более кодировку сайта, всеже считать текстовый нормально
гугол мне выдает всякую хрень не связанную с вопросом
iconv("cp1251", "utf-8", file_get_contents("filename"))
Вместо <submit> делаешь <button>, вешаешь на него onclick-событие. Когда событие происходит, выполняется js функция которую ты привязал, она собирает нужные данные формы, создает XMLHttpRequest объект, в .open() указываешь ему хттп-метод и урл куда слать, если нужно знать результат отправки на .onreadystatechange указываешь колбек функцию которая будет обрабатывать результат и отсылаешь реквест через .send(данные запроса). Если выбран метод GET то будет .send(null), если POST, то строка в виде "поле1=значение1&поле2=значение2".
спасибо, но я имел в виду без нажатия на что либо, чтобы не нужно было никуда нажимать, а само сохранялось когда поле заполнено
https://gist.github.com/codedokode/d7e7f11449fc3bcb24b4
Задача рассчитана на то что бы делать её в ООП? Если делать в ООП то как правильнее описать класс, элементом класса будет каждое поле формы? То есть
class student {
public $name;
public $lastname;
...
}
Как лучше сделать возможность редактирования, когда я писал в обычном процедурном стиле это задание я использовал в случае правильно записи в базу данных такой код
$_SESSION["student"] = 1; //метка регистрации
\t$_SESSION["id"] = mysql_insert_id(); //Последний айди добавленный в базу
Потом по вот этому $_SESSION["id"] для записи в которой такой же id выводил ссылку по которой можно пройти на редактирование данных. Но что то подсказывает мне этот метод не правильный.
Ну тогда надо повесить событие на поле. Там целый зоопарк их, в зависимости от того что тебе конкретно надо, есть onchange, onkeyup, onkeydown, oninput. Функция будет вызываться на изменение поля, будешь смотреть в ней, достаточно ли в поле инфы, чтоб её считать валидной и отправлять XHR если да.
margin
margin-top: 0;
я думал поле считается пустым до нажатия сабмит. как прочитать его с помощью js?
Возможно прислал хуёвое качество, обрезанное сильно, с рисунками или типа того.
Почему бы тогда не написать о качестве в письме? Вот и понимай как хочешь, что значит incomplete и чего им не хватает.
Подскажите хорошее облачное хранилище, чтобы моя локальная папка с проектом синхронизировалась с этим облаком.
Дропбокс, гугл драйв не подходят так как синхронизируются только данные внутри их корневых папок. Яндекс диск не подходит так как он не отслеживает изменения файлов и синхронизирует только если появляется/удаляется файл. Спасибо
на github.com , у ОПа есть гайд по нему.
Решил попробовать себя в этой сфере, но так как в программировании я полный ноль, то помощь мне нужна даже в простейших заданиях.
Я все сделал неправильно, да?
http://codepad.org/Ye6WI4sj
>Я все сделал неправильно, да?
>codepad
Да. У меня на этот сайт аллергия. Выкладывай на ideone.
Ок спасибо, я просто подумал, что скрипт без этой фигни закольцуется,лол.
Я же только впервые в глаза увидел это все, ладно, пошел дальше вкуривать.
и две подстроки искались бы отдельно во всех столбцах?
если резать строку по пробелам, то приходится для разного количества подстрок разные запросы делать,
это наверно не правильно
Поясните 1 нюанс по сессиям.
Вот есть у меня файл login.php который выглядит примерно так: http://ideone.com/mBz8XW
Вот при удачном логине я начинаю сессию и кладу в массив $_SESSION два элемента. Далее они используются у меня в основном файле index.php и всё такое. Пока что всё правильно реализовано? Теперь у меня главный вопрос: как правильно делать разлогинивание пользователя через сессии? Не просто же ансетать все переменные которые ты клал в этот массив во время логина?
Что мне делать?
Забыл про ничью, вот последняя правка.
Понимаю что фигней пока занимаюсь, но все же.
http://ideone.com/ZtpEkV
У меня слабый навык декомпозиции (плохо понимаю, как разбить задачу на подзадачи).
Что мне делать?
О, хорошо что ты написал. Я собирался посмотреть твой проект, но все откладывал на потом.
Вообще, уровень проекта довольно высокий, я вижу что ты разобрался и с асинхронной работой с сокетами, и с протоколами HTTP/Websocket, и с ООП.
Вот советы и замечания по коду.
Не вижу где в репозитории конфигурация для mongoDB. Например, где определяются индексы? Где создаются коллекции?
У тебя немного странно разложены файлы по папкам. Обычно делают одну папку для сущностей (вроде RoomEvent, RoomUser), другую для мапперов, и т.д. У тебя же как-то все получилось разбросано по разным папкам.
Не очень понятно зачем наследовать RatchetServer от Pimple. Обычно наследование используют чтобы расширить наследуемый класс, но RatchetServer это явно не расширение для DI контейнера. Возможно, ты копировал схему котору. использует Silex, но мне кажется это неудачная идея.
Далее, напрягает то, что у тебя там по факту 2 контейнера и приходится определять сервисы по 2 раза: в RatchetServer, и в Webapp. Гораздо лучше если бы и websocket сервер и приложение разделяли общий контейнер. Вполне можно использовать тот, что в Webapp.
Далее, про реализацию ODM (маппинга сущностей на объекты в MongoDB). Обычно в мапперах реализуют подход IdentityMap: http://design-pattern.ru/patterns/identity-map.html
При этом подходе одной сущности всегда соответствует ровно один объект. Если мы 2 раза пытаемся загрузить пользователя с одним и тем же id, то мы получаем тот же самый объект. При этом если ты хочешь реализовать IdentityMap сам, ты натолкнешься на утечку памяти: так как объекты только добавляются туда и никогда не удаляются, эта структура начинает неограниченно расти в памяти. При этом удалять объекты ты не можешь так как не знаешь, исользуются ли они сейчас где-то или нет. Решением этой проблемы является WeakMap — специальная структура, которая позволяет сборщику мусора собирать объекты из нее, если они больше нигде не используются: http://php.net/manual/ru/book.weakref.php
WeakMap давно уже есть в других языках, вроде Java, и скоро появится в браузерах: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
Если WeakMap недоступен, то придется использовать другие решения, вроде явного удаления сущностей из IdentityMap.
Как альтернатива, можно попробовать применить готовый ODM вроде https://github.com/doctrine/mongodb-odm
Не уверен, впрочем, что в твоем маленьком проекте это обязательно. Наверно, можно и без этого прожить, но знать про такую штуку стоит.
Класс RoomEvent наверно стоило сделать абстрактным.
Далее, не очень понятно по каким принципам распределен код по классам RatchetServer, Chat, RoomUserHandler, RoomEventHandler, такое ощущение что они примерно одним и тем же занимаются. Было бы логично оставить RatchetServer работу с соединениями, а всю логику поместить например в Chat. Зачем вообще нужны Handler-классы?
В приложениях обычно делают слой сервисов, который находится на уровень выше мапперов ( http://martinfowler.com/eaaCatalog/serviceLayer.html ), но в твоем случае получается 2 уровня: Handler и Chat, и один из уровней тут явно лишний. То есть лучше сделать 1 или несколько классов-сервисов, без Handler классов.
> public function leftUserFromRoom(User $user, $roomName)
> public function removeUserFromRoom(User $user, $roomName)
Названия очень неудачные, прямо следуют совету отсюда: http://learn.javascript.ru/write-unmain-code#хитрые-синонимы
Насчет проблемы с заходом пользователя с нескольких устройств или вкладок, тебе надо вместо пользователя ввести понятие «соединения». Это относится и к удалению пользователя из комнаты (надо удалять соединение) и к untrackUser в UserHeartbeat.
> https://github.com/d-beekeeper/ratchat/blob/master/app/User/UserRegister.php#L39
> public function __construct(Webapp $app,$username,$password,$checkPass)
Очень странно что в конструктор передаются имя и пароль. Наверно логичнее сделать класс-сервис для регистрации пользователей, а не класс для регистрации единственного пользователя. Тем более что в функцию registerUser(User $user) ты и так передаешь объект-пользователя.
> https://github.com/d-beekeeper/ratchat/blob/master/app/ADataMapper.php#L32
> protected function convertId($_id)
Это очень странная функция. Ее не должно быть и она выглядит как костыль. Потому что создается ощущение что ты сам не знаешь в каком формате у тебя хранится id. нужно сделать, чтобы он везде хранился в единообразном виде, а не как попало. Особенно вот этот код шедеврально выглядит:
> if (!\MongoId::isValid($_id)) {
> $_id = substr(md5($_id),0,24);
Это какой-то кривой костыль, явно.
То же самое и с датой. Ты можешь делать преобразование id и дат в маппере при сохранении/загрузке: маппер для этого и предназначен вообще-то.
> @param RoomEvent|RoomEvent[] $roomsEvents
Мне кажется, так делать не стоит. Это и усложняет код и повышает вероятность пропустить ошибку. Тип входных параметров функции должен быть однозначно определен.
> $roomUser->user = $this->cleanupUserInfo($roomUser->user);
Это (фильтрацию аттрибутов) надо делать на этапе экспорта из объектов в массив (для кодирования в JSON). Ты даже можешь сделать у сущности метод вроде getPublicData() или делать фильтрацию снаружи сущности.
Также, получается не очень хорошая ситуация: ты в BackendToFrontendMessage при преобразовании в JSON удаляешь часть полей и у пользователей, а потом восстанавливаешь из JSON. В итоге у нас в приложении ходит 2 набора сущностей: полноценные и с отрезанными полями. Это провоцирует баги.
> https://github.com/d-beekeeper/ratchat/blob/master/app/BackendToFrontendMessage.php#L56
> public function fromJson($jsonString)
Обычно такие функции делают статическими
Внешних пользователей обычно делают как отдельную сущность, которая связана с внутренними пользователями соотношением много-к-одному. Это позволяет например с нескольких внешних аккаунтов входить в один и тот же внутренний.
> https://github.com/d-beekeeper/ratchat/blob/master/app/User/User.php#L73
> if (isset($this->username)) $attrs['username'] = $this->username;
Не очень понятно, почему ты прововеряешь равенство поля null через isset, и не очень понятно почему такие поля не попадают в массив. В чем удобство того, что мы имеем массив с неизвестным числом полей?
> public function receiveByAttributes(User $user)
Тоже странная функция. Как я понимаю, она используется для проверки уникальности имени, ну так и надо сделать функцию isUsernameUnique
> https://github.com/d-beekeeper/ratchat/blob/master/app/VkAuth/VkApi.php#L43
тут наверно returnUrl надо пропустить через urlencode
О, хорошо что ты написал. Я собирался посмотреть твой проект, но все откладывал на потом.
Вообще, уровень проекта довольно высокий, я вижу что ты разобрался и с асинхронной работой с сокетами, и с протоколами HTTP/Websocket, и с ООП.
Вот советы и замечания по коду.
Не вижу где в репозитории конфигурация для mongoDB. Например, где определяются индексы? Где создаются коллекции?
У тебя немного странно разложены файлы по папкам. Обычно делают одну папку для сущностей (вроде RoomEvent, RoomUser), другую для мапперов, и т.д. У тебя же как-то все получилось разбросано по разным папкам.
Не очень понятно зачем наследовать RatchetServer от Pimple. Обычно наследование используют чтобы расширить наследуемый класс, но RatchetServer это явно не расширение для DI контейнера. Возможно, ты копировал схему котору. использует Silex, но мне кажется это неудачная идея.
Далее, напрягает то, что у тебя там по факту 2 контейнера и приходится определять сервисы по 2 раза: в RatchetServer, и в Webapp. Гораздо лучше если бы и websocket сервер и приложение разделяли общий контейнер. Вполне можно использовать тот, что в Webapp.
Далее, про реализацию ODM (маппинга сущностей на объекты в MongoDB). Обычно в мапперах реализуют подход IdentityMap: http://design-pattern.ru/patterns/identity-map.html
При этом подходе одной сущности всегда соответствует ровно один объект. Если мы 2 раза пытаемся загрузить пользователя с одним и тем же id, то мы получаем тот же самый объект. При этом если ты хочешь реализовать IdentityMap сам, ты натолкнешься на утечку памяти: так как объекты только добавляются туда и никогда не удаляются, эта структура начинает неограниченно расти в памяти. При этом удалять объекты ты не можешь так как не знаешь, исользуются ли они сейчас где-то или нет. Решением этой проблемы является WeakMap — специальная структура, которая позволяет сборщику мусора собирать объекты из нее, если они больше нигде не используются: http://php.net/manual/ru/book.weakref.php
WeakMap давно уже есть в других языках, вроде Java, и скоро появится в браузерах: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
Если WeakMap недоступен, то придется использовать другие решения, вроде явного удаления сущностей из IdentityMap.
Как альтернатива, можно попробовать применить готовый ODM вроде https://github.com/doctrine/mongodb-odm
Не уверен, впрочем, что в твоем маленьком проекте это обязательно. Наверно, можно и без этого прожить, но знать про такую штуку стоит.
Класс RoomEvent наверно стоило сделать абстрактным.
Далее, не очень понятно по каким принципам распределен код по классам RatchetServer, Chat, RoomUserHandler, RoomEventHandler, такое ощущение что они примерно одним и тем же занимаются. Было бы логично оставить RatchetServer работу с соединениями, а всю логику поместить например в Chat. Зачем вообще нужны Handler-классы?
В приложениях обычно делают слой сервисов, который находится на уровень выше мапперов ( http://martinfowler.com/eaaCatalog/serviceLayer.html ), но в твоем случае получается 2 уровня: Handler и Chat, и один из уровней тут явно лишний. То есть лучше сделать 1 или несколько классов-сервисов, без Handler классов.
> public function leftUserFromRoom(User $user, $roomName)
> public function removeUserFromRoom(User $user, $roomName)
Названия очень неудачные, прямо следуют совету отсюда: http://learn.javascript.ru/write-unmain-code#хитрые-синонимы
Насчет проблемы с заходом пользователя с нескольких устройств или вкладок, тебе надо вместо пользователя ввести понятие «соединения». Это относится и к удалению пользователя из комнаты (надо удалять соединение) и к untrackUser в UserHeartbeat.
> https://github.com/d-beekeeper/ratchat/blob/master/app/User/UserRegister.php#L39
> public function __construct(Webapp $app,$username,$password,$checkPass)
Очень странно что в конструктор передаются имя и пароль. Наверно логичнее сделать класс-сервис для регистрации пользователей, а не класс для регистрации единственного пользователя. Тем более что в функцию registerUser(User $user) ты и так передаешь объект-пользователя.
> https://github.com/d-beekeeper/ratchat/blob/master/app/ADataMapper.php#L32
> protected function convertId($_id)
Это очень странная функция. Ее не должно быть и она выглядит как костыль. Потому что создается ощущение что ты сам не знаешь в каком формате у тебя хранится id. нужно сделать, чтобы он везде хранился в единообразном виде, а не как попало. Особенно вот этот код шедеврально выглядит:
> if (!\MongoId::isValid($_id)) {
> $_id = substr(md5($_id),0,24);
Это какой-то кривой костыль, явно.
То же самое и с датой. Ты можешь делать преобразование id и дат в маппере при сохранении/загрузке: маппер для этого и предназначен вообще-то.
> @param RoomEvent|RoomEvent[] $roomsEvents
Мне кажется, так делать не стоит. Это и усложняет код и повышает вероятность пропустить ошибку. Тип входных параметров функции должен быть однозначно определен.
> $roomUser->user = $this->cleanupUserInfo($roomUser->user);
Это (фильтрацию аттрибутов) надо делать на этапе экспорта из объектов в массив (для кодирования в JSON). Ты даже можешь сделать у сущности метод вроде getPublicData() или делать фильтрацию снаружи сущности.
Также, получается не очень хорошая ситуация: ты в BackendToFrontendMessage при преобразовании в JSON удаляешь часть полей и у пользователей, а потом восстанавливаешь из JSON. В итоге у нас в приложении ходит 2 набора сущностей: полноценные и с отрезанными полями. Это провоцирует баги.
> https://github.com/d-beekeeper/ratchat/blob/master/app/BackendToFrontendMessage.php#L56
> public function fromJson($jsonString)
Обычно такие функции делают статическими
Внешних пользователей обычно делают как отдельную сущность, которая связана с внутренними пользователями соотношением много-к-одному. Это позволяет например с нескольких внешних аккаунтов входить в один и тот же внутренний.
> https://github.com/d-beekeeper/ratchat/blob/master/app/User/User.php#L73
> if (isset($this->username)) $attrs['username'] = $this->username;
Не очень понятно, почему ты прововеряешь равенство поля null через isset, и не очень понятно почему такие поля не попадают в массив. В чем удобство того, что мы имеем массив с неизвестным числом полей?
> public function receiveByAttributes(User $user)
Тоже странная функция. Как я понимаю, она используется для проверки уникальности имени, ну так и надо сделать функцию isUsernameUnique
> https://github.com/d-beekeeper/ratchat/blob/master/app/VkAuth/VkApi.php#L43
тут наверно returnUrl надо пропустить через urlencode
Вместо curl в VkApi удобнее использовать нормальный ООП HTTP клиент, например Guzzle, это еще и сделает код гибким и тестируемым, позволив передать вместо Guzzle заглушку, и даст готовые объекты Request/Response (кстати на Request/Response наконец-то готовится стандарт: https://github.com/php-fig/fig-standards/blob/master/proposed/http-message.md ).
> $decoded = json_decode($string,true);
> if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) {
При ошибке до if управление скорее всего не дойдет так как json_decode выдает Warning который некоторые фреймворки (не знаю как насчет Silex) превратят в ErrorEcxeption. Если ты хочешь обрабатывать ошибку сам придется поставить @. Это конечно бардак, система ошибок в PHP.
> https://github.com/d-beekeeper/ratchat/blob/master/app/VkAuth/VkAuthProvider.php#L40
> throw new AuthenticationException(...);
Здесь ты теряешь информацию из пойманного исключения. Чтобы этого не было, обычно исключения разрешают передать «предыдущее» исключение в конструктор. В доументации легко увидеть соответствующий параметр: http://api.symfony.com/2.1/Symfony/Component/Security/Core/Exception/AuthenticationException.html
> public function receiveByAttributes(User $user)
Тоже не очень удачно сделана функция, лучше явно передавать массив условий.
> TODO следующий блок нужно вынести в отдельный скрипт, исполняемый кроном раз в N секунд, где N < UserHeartbeater::MAX_USER_DEAD_TIME/2
Вообще, ты мог бы засунуть это в server.php, он же асинхронный и он может делать действие раз в N секунд. И запускать в отдельном процессе, чтобы он не блокировал обслуживание вебсокетов. Тем более что у крона минимальная периодичность запуска минута.
А сейчас у тебя если никто не обновит страницу чата, старые сообщения не удалятся.
> https://github.com/d-beekeeper/ratchat/blob/master/web/index.php#L63
> $app->match('/chat',function (Request $request) use($app) {
тут что-то многовато кода. Хоть бы по функциям разбил.
> https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L66
> <div id="chat-message-template" style="display: none;">
Шаблоны гораздо удобнее и семантичнее хранить в теге скрипт: http://learn.javascript.ru/templates#хранение-шаблона-в-документе
Более того, ты бы мог использовать стандартный шаблонизатор, тысячи их:
- JsRender http://habrahabr.ru/post/148573/
- handlebars
- другие, тысяи их: http://garann.github.io/template-chooser/
Кстати, у них у большинства очень странный ситаксис. Нет бы использовать синтаксис twig, нет, хотим изобретать велосипед и наступать на те же грабли.
Более того, у тебя есть дублирование шаблонов:
https://github.com/d-beekeeper/ratchat/blob/master/views/_messages.twig#L3
https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L67
От него можно избавиться за счет макросов twig.
> <script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js">
Не советую так делать. Этим ты только повышаешь даунтайм приложения. Храни скрипты на своем сервере, не бери пример с js-хипстеров.
> {{ app.security.token.user.username }}
> app.session.getFlashBag.get('vk_error')
Стоит явно передавать это в шаблонизатор, а то шаблонизатор очень глубоко в недра приложения лезет.
> https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L21
Что за странный <a> без href?
> <meta name="viewport" content="width=device-width, initial-scale=1">
Это ты скопировал или у тебя правда адаптивный дизайн?
> options.chat.find('#chat-message-template')
Вместо того чтобы передавать словарь с одим параметром, лучше сразу передавать chat в конструктор. Вообще, options имеет смысл когда опций куча и большинство не обязательны, и это по моему не очень хороший подход. Тут например можно опечататься и никакого сообщения об ошибке не будет.
> options.chat.data('eventSequenceNum'),
Вообще тут наверно проще без data-аттрибутов обойтись и передать число прямо в конструктор или метод setSequenceNum.
> Если не удалось установить ws connection, или он поработал и разорвался - делаем fallback к ajax transport
Мне кажется, если вебсокет отвалился, но соединение возможно, лучше повторно соединяться через WS. Отваливающиеся соединения — обычное дело.
У тебя на клиенте есть какое-то ограничение на число отображаемых сообщений? Браузеры тормозят при большом числе DOM нод. Например, нет особого смысла отображать все сообщения, достаточно последних N, и в неактивных комнатах тоже, а добавлять новые можно при прокрутке. Посмотри, как например скайп это делает (он отображает сообщения внутри WebView, встроенного браузера, если я ничего не путаю).
> alert('Ошибка: ' + value);
alert очень плохой с точки зрения юзабилити.
> this.chatRooms[event.chatRoom].addMessages
Нет проверки что такая комната есть.
> this._$sendbtns.attr('disabled','disabled');
disabled надо ставить через prop(), так как это свойство. Атрибут лишь задает его начальное значение. Не путай свойства и атрибуты: http://stackoverflow.com/questions/5874652/prop-vs-attr
> Chat.prototype._enableControlBtns = function () {
> this._$roomAddBtn.click(function () {
удалять/добавлять события — признак плохой архитектуры. Используй disabled или переменную-флаг лучше.
> if (code==2 || code==3) {
Там конастант нет что ли? Что за магические числа?
> https://github.com/d-beekeeper/ratchat/blob/master/web/js/chat.js#L290
> if ($(this).queue().length == 0)
Это вообще где-то в документации описано? Почему ты в объект jQuery передаешь непонятно что? Если ты хочешь исплоьзовать очередь из jQuery лучше нормально создать отдельный объект через this.queue = $().queue( );
> $messageTemplate.find('a.msg-template-avatar-link').attr('href',avatar);
Тут явно стоит использовать шаблонизатор
В общем, такой вот набор советов по улучшению. Но в общем, код на очень хорошем уровне.
Еще мне кажется, все-таки стоит сделать тесты производительности. Вебсокеты используются как раз для обработки большого числа соединений, разработики монго много говорят про ее производительность, ты явно хотел сделать высокопроизводительный чат (хотя, он же работает в одном процессе и не масштабируется) и разумеется все это должно быть проверено тестами, так как на словах можно сказать что угодно. Ну и если ты хочешь стать highload разработчиком, то это полезное умение.
Большие компании делают такие тесты и иногда даже изобретают свои инструменты: http://habrahabr.ru/company/yandex/blog/202020/
Для простых ситуаций вполне может хватить простых инструментов вроде ab или siege. ab (Apache Benchmark) просто шлет указанное число раз в указанное число потоков один и тот же запрос. Он примитивный, но позволяет оценить скорость обработки запросов. siege сложнее, он может слать запросы на разные URL по заранее составленному списку, имитируя действия разных пользователей. Также, ты можешь отправлять запросы например своим скриптом на php c http клиентом вроде guzzle.
Есть еще относительно мощный Apache JMeter, но с ним я не работал: http://habrahabr.ru/post/140310/
Искать узкие места в скрипте можно с помощью профайлера, входящего в xdebug. Профайлинг можно запускать как для веб-приложения, так и для Cli скрипта при передаче определенных параметров. Файл с результатами можно просмотреть через программы вроде KCacheGrind или WinCacheGrind.
С помощью нагрузочного тестирования можно заметить проблемы при обработке большого числа соединений или сообщений: увеличение времени ответа, увеличение потребления памяти, падения приложения, рост числа ошибок.
Вот что, по моему, стоит протестировать:
- изменение времени добавления сообщения по мере их накопления. Просто сделай скрипт который отправляет сообщения в чат и меряй время обработки запроса. Например, время на отправку 1, 10, 100, 1000, 10000, 100000 запросов, а потом посмотри, нет ли деградации по мере накопления сообщений
- то же самое но с N подключенными слушателями
- проверку на максимальное чило клиентов (не уверен что это можно сделать стандартными средствами). Соединяешься с чатом с N клиентов, и смотришь как меняется время ответа с ростом числа клиентов и не упадет ли приложение
- то же самое, но каждый клиент отправляет 1 сообщение
- время загрузки страницы с чатом при наличии N сообщений в чате
- также, можно померять производительность ajax- и POST-транспорта, но это не так критично, так как мы предполагаем что использовать будет вебсокет.
В общем, тестирование дало бы тебе полезные навыки и наверняка обнаружило бы узкие места в приложении. Для чистоты эксперимента перед каждым тестом надо очищать базу.
Кстати, как у тебя с очисткой старых сообщений? Они когда-нибудь очищаются? Или производительность по мере их накопления деградирует?
Ну и вторая вещь, которой можно было бы заняться, это покрыть приложение тестами. Вот например мой обзорный урок про виды тестирования: https://gist.github.com/codedokode/a455bde7d0748c0a351a Почитай. может интересно станет с этим разобраться.
Вместо curl в VkApi удобнее использовать нормальный ООП HTTP клиент, например Guzzle, это еще и сделает код гибким и тестируемым, позволив передать вместо Guzzle заглушку, и даст готовые объекты Request/Response (кстати на Request/Response наконец-то готовится стандарт: https://github.com/php-fig/fig-standards/blob/master/proposed/http-message.md ).
> $decoded = json_decode($string,true);
> if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) {
При ошибке до if управление скорее всего не дойдет так как json_decode выдает Warning который некоторые фреймворки (не знаю как насчет Silex) превратят в ErrorEcxeption. Если ты хочешь обрабатывать ошибку сам придется поставить @. Это конечно бардак, система ошибок в PHP.
> https://github.com/d-beekeeper/ratchat/blob/master/app/VkAuth/VkAuthProvider.php#L40
> throw new AuthenticationException(...);
Здесь ты теряешь информацию из пойманного исключения. Чтобы этого не было, обычно исключения разрешают передать «предыдущее» исключение в конструктор. В доументации легко увидеть соответствующий параметр: http://api.symfony.com/2.1/Symfony/Component/Security/Core/Exception/AuthenticationException.html
> public function receiveByAttributes(User $user)
Тоже не очень удачно сделана функция, лучше явно передавать массив условий.
> TODO следующий блок нужно вынести в отдельный скрипт, исполняемый кроном раз в N секунд, где N < UserHeartbeater::MAX_USER_DEAD_TIME/2
Вообще, ты мог бы засунуть это в server.php, он же асинхронный и он может делать действие раз в N секунд. И запускать в отдельном процессе, чтобы он не блокировал обслуживание вебсокетов. Тем более что у крона минимальная периодичность запуска минута.
А сейчас у тебя если никто не обновит страницу чата, старые сообщения не удалятся.
> https://github.com/d-beekeeper/ratchat/blob/master/web/index.php#L63
> $app->match('/chat',function (Request $request) use($app) {
тут что-то многовато кода. Хоть бы по функциям разбил.
> https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L66
> <div id="chat-message-template" style="display: none;">
Шаблоны гораздо удобнее и семантичнее хранить в теге скрипт: http://learn.javascript.ru/templates#хранение-шаблона-в-документе
Более того, ты бы мог использовать стандартный шаблонизатор, тысячи их:
- JsRender http://habrahabr.ru/post/148573/
- handlebars
- другие, тысяи их: http://garann.github.io/template-chooser/
Кстати, у них у большинства очень странный ситаксис. Нет бы использовать синтаксис twig, нет, хотим изобретать велосипед и наступать на те же грабли.
Более того, у тебя есть дублирование шаблонов:
https://github.com/d-beekeeper/ratchat/blob/master/views/_messages.twig#L3
https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L67
От него можно избавиться за счет макросов twig.
> <script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js">
Не советую так делать. Этим ты только повышаешь даунтайм приложения. Храни скрипты на своем сервере, не бери пример с js-хипстеров.
> {{ app.security.token.user.username }}
> app.session.getFlashBag.get('vk_error')
Стоит явно передавать это в шаблонизатор, а то шаблонизатор очень глубоко в недра приложения лезет.
> https://github.com/d-beekeeper/ratchat/blob/master/views/chat.twig#L21
Что за странный <a> без href?
> <meta name="viewport" content="width=device-width, initial-scale=1">
Это ты скопировал или у тебя правда адаптивный дизайн?
> options.chat.find('#chat-message-template')
Вместо того чтобы передавать словарь с одим параметром, лучше сразу передавать chat в конструктор. Вообще, options имеет смысл когда опций куча и большинство не обязательны, и это по моему не очень хороший подход. Тут например можно опечататься и никакого сообщения об ошибке не будет.
> options.chat.data('eventSequenceNum'),
Вообще тут наверно проще без data-аттрибутов обойтись и передать число прямо в конструктор или метод setSequenceNum.
> Если не удалось установить ws connection, или он поработал и разорвался - делаем fallback к ajax transport
Мне кажется, если вебсокет отвалился, но соединение возможно, лучше повторно соединяться через WS. Отваливающиеся соединения — обычное дело.
У тебя на клиенте есть какое-то ограничение на число отображаемых сообщений? Браузеры тормозят при большом числе DOM нод. Например, нет особого смысла отображать все сообщения, достаточно последних N, и в неактивных комнатах тоже, а добавлять новые можно при прокрутке. Посмотри, как например скайп это делает (он отображает сообщения внутри WebView, встроенного браузера, если я ничего не путаю).
> alert('Ошибка: ' + value);
alert очень плохой с точки зрения юзабилити.
> this.chatRooms[event.chatRoom].addMessages
Нет проверки что такая комната есть.
> this._$sendbtns.attr('disabled','disabled');
disabled надо ставить через prop(), так как это свойство. Атрибут лишь задает его начальное значение. Не путай свойства и атрибуты: http://stackoverflow.com/questions/5874652/prop-vs-attr
> Chat.prototype._enableControlBtns = function () {
> this._$roomAddBtn.click(function () {
удалять/добавлять события — признак плохой архитектуры. Используй disabled или переменную-флаг лучше.
> if (code==2 || code==3) {
Там конастант нет что ли? Что за магические числа?
> https://github.com/d-beekeeper/ratchat/blob/master/web/js/chat.js#L290
> if ($(this).queue().length == 0)
Это вообще где-то в документации описано? Почему ты в объект jQuery передаешь непонятно что? Если ты хочешь исплоьзовать очередь из jQuery лучше нормально создать отдельный объект через this.queue = $().queue( );
> $messageTemplate.find('a.msg-template-avatar-link').attr('href',avatar);
Тут явно стоит использовать шаблонизатор
В общем, такой вот набор советов по улучшению. Но в общем, код на очень хорошем уровне.
Еще мне кажется, все-таки стоит сделать тесты производительности. Вебсокеты используются как раз для обработки большого числа соединений, разработики монго много говорят про ее производительность, ты явно хотел сделать высокопроизводительный чат (хотя, он же работает в одном процессе и не масштабируется) и разумеется все это должно быть проверено тестами, так как на словах можно сказать что угодно. Ну и если ты хочешь стать highload разработчиком, то это полезное умение.
Большие компании делают такие тесты и иногда даже изобретают свои инструменты: http://habrahabr.ru/company/yandex/blog/202020/
Для простых ситуаций вполне может хватить простых инструментов вроде ab или siege. ab (Apache Benchmark) просто шлет указанное число раз в указанное число потоков один и тот же запрос. Он примитивный, но позволяет оценить скорость обработки запросов. siege сложнее, он может слать запросы на разные URL по заранее составленному списку, имитируя действия разных пользователей. Также, ты можешь отправлять запросы например своим скриптом на php c http клиентом вроде guzzle.
Есть еще относительно мощный Apache JMeter, но с ним я не работал: http://habrahabr.ru/post/140310/
Искать узкие места в скрипте можно с помощью профайлера, входящего в xdebug. Профайлинг можно запускать как для веб-приложения, так и для Cli скрипта при передаче определенных параметров. Файл с результатами можно просмотреть через программы вроде KCacheGrind или WinCacheGrind.
С помощью нагрузочного тестирования можно заметить проблемы при обработке большого числа соединений или сообщений: увеличение времени ответа, увеличение потребления памяти, падения приложения, рост числа ошибок.
Вот что, по моему, стоит протестировать:
- изменение времени добавления сообщения по мере их накопления. Просто сделай скрипт который отправляет сообщения в чат и меряй время обработки запроса. Например, время на отправку 1, 10, 100, 1000, 10000, 100000 запросов, а потом посмотри, нет ли деградации по мере накопления сообщений
- то же самое но с N подключенными слушателями
- проверку на максимальное чило клиентов (не уверен что это можно сделать стандартными средствами). Соединяешься с чатом с N клиентов, и смотришь как меняется время ответа с ростом числа клиентов и не упадет ли приложение
- то же самое, но каждый клиент отправляет 1 сообщение
- время загрузки страницы с чатом при наличии N сообщений в чате
- также, можно померять производительность ajax- и POST-транспорта, но это не так критично, так как мы предполагаем что использовать будет вебсокет.
В общем, тестирование дало бы тебе полезные навыки и наверняка обнаружило бы узкие места в приложении. Для чистоты эксперимента перед каждым тестом надо очищать базу.
Кстати, как у тебя с очисткой старых сообщений? Они когда-нибудь очищаются? Или производительность по мере их накопления деградирует?
Ну и вторая вещь, которой можно было бы заняться, это покрыть приложение тестами. Вот например мой обзорный урок про виды тестирования: https://gist.github.com/codedokode/a455bde7d0748c0a351a Почитай. может интересно станет с этим разобраться.
Ты можешь выставлять заголовки (и ставить куки) пока не начал что-то выводить. Если начал то поздно так как то что ты выводишь идет в теле ответа, а заголовки идут перед телом.
>>438437
Вот ты бы лучше это безобразие исправил:
> ($name, $attackLow, $attackHigh, $health, $armorLow, $armorHigh, $block, $dodgeCrit, $crit, $charisma, $agility, $skill)
Запутаться же проще простого
> construct($heroFirst, $heroSecond)
Тут нужен тайп-хинт: http://php.net/manual/ru/language.oop5.typehinting.php
> global $phrasesDodge;
Глобальные переменные это плохо. Лучше сделать в Game метод getRandomPhrase(). Константы не нужны так как они нигде не используются, а выбрать случайный элемент можно и без них.
> можно ли делать так как я сделал в function fillNotFilledStrings()?
Вообще, плохой код. Зачем ты в классе Game снаружи меняешь свойтва героев. если можно просто сделать методы у героев и поместить код туда?
Этот код вообще абсолютно неправильный:
> $this->heroes[0]->doubleHit = $charAbs;
Шанс на двойной удар это не свойство героя так как оно зависит от соперника. Значит оно должно вычисляться в методе а не храниться в свойстве.
> $this->heroes[0]->hitChance = round(($this->heroes[0]->skill
надо сделать метод $hero->getHitChance вместо этого
> $this->heroes[0]->enemyBlock = $this->heroes[1]->block;
Это вообще бессмысленный код. Зачем копировать свойство если мы всегда можем взять его из второго героя?
Вообще, странная идея хранить в герое свойства другого героя. Бред же. А если драка будет 3 на 3, ты в герое будешь свойства каждого соперника хранить?
Функцию fillNotFilledStrings() надо удалить и лишние свойства тоже удалить и сделать методы в классе Hero вместо этого.
> private function makeOneHit($hero)
Почему передается только один герой? Он сам с собой дерется что ли? Надо сделать чтобы передавалось 2 героя, кто с кем дерется.
> if ($this->heroes[0]->health < $secondDamage) {
для этого лучше сделать метод. Более того, вот это вот heroes[0] смотрится плохо. Нельзя циклом обойти, раз уж у тебя массив?
> return 1;
Что это за магические числа? Непонятно что это значит? Кто победил? Тогда логичнее возвращать не число.а сам объект и null в случае ничьи.
> мощный рубящий удар, цель удара чудом избежала чудовищного удара.
Что-то тут у тебя слово «удар» 3 раза повторяется. Лучше бы избегать таких повторов, а то как-то не очень хорошо смотрится текст.
> if ($this->heroes[0]->health < $secondDamage) {
> $this->heroes[0]->health = 1;
> $this->heroes[0]->health -= $secondDamage;
Лучше сделать у героя методы takeDamage($damage) и isAlive() Ты же вместо того чтобы положить относящийся к герою код в его класс, разимазываешь его равномерно по всей программе. В ООП объект это набор данных + методы для управления ими. А ты не хочешь делать методы, а исплоьзуешь объект как массив, зря.
Вообще, чтобы ты лучше прочуствовал эту концепцию, сделай свойства закрытыми, то есть не public, а private и используй методы для доступа к ним и их изменения.
Ты можешь выставлять заголовки (и ставить куки) пока не начал что-то выводить. Если начал то поздно так как то что ты выводишь идет в теле ответа, а заголовки идут перед телом.
>>438437
Вот ты бы лучше это безобразие исправил:
> ($name, $attackLow, $attackHigh, $health, $armorLow, $armorHigh, $block, $dodgeCrit, $crit, $charisma, $agility, $skill)
Запутаться же проще простого
> construct($heroFirst, $heroSecond)
Тут нужен тайп-хинт: http://php.net/manual/ru/language.oop5.typehinting.php
> global $phrasesDodge;
Глобальные переменные это плохо. Лучше сделать в Game метод getRandomPhrase(). Константы не нужны так как они нигде не используются, а выбрать случайный элемент можно и без них.
> можно ли делать так как я сделал в function fillNotFilledStrings()?
Вообще, плохой код. Зачем ты в классе Game снаружи меняешь свойтва героев. если можно просто сделать методы у героев и поместить код туда?
Этот код вообще абсолютно неправильный:
> $this->heroes[0]->doubleHit = $charAbs;
Шанс на двойной удар это не свойство героя так как оно зависит от соперника. Значит оно должно вычисляться в методе а не храниться в свойстве.
> $this->heroes[0]->hitChance = round(($this->heroes[0]->skill
надо сделать метод $hero->getHitChance вместо этого
> $this->heroes[0]->enemyBlock = $this->heroes[1]->block;
Это вообще бессмысленный код. Зачем копировать свойство если мы всегда можем взять его из второго героя?
Вообще, странная идея хранить в герое свойства другого героя. Бред же. А если драка будет 3 на 3, ты в герое будешь свойства каждого соперника хранить?
Функцию fillNotFilledStrings() надо удалить и лишние свойства тоже удалить и сделать методы в классе Hero вместо этого.
> private function makeOneHit($hero)
Почему передается только один герой? Он сам с собой дерется что ли? Надо сделать чтобы передавалось 2 героя, кто с кем дерется.
> if ($this->heroes[0]->health < $secondDamage) {
для этого лучше сделать метод. Более того, вот это вот heroes[0] смотрится плохо. Нельзя циклом обойти, раз уж у тебя массив?
> return 1;
Что это за магические числа? Непонятно что это значит? Кто победил? Тогда логичнее возвращать не число.а сам объект и null в случае ничьи.
> мощный рубящий удар, цель удара чудом избежала чудовищного удара.
Что-то тут у тебя слово «удар» 3 раза повторяется. Лучше бы избегать таких повторов, а то как-то не очень хорошо смотрится текст.
> if ($this->heroes[0]->health < $secondDamage) {
> $this->heroes[0]->health = 1;
> $this->heroes[0]->health -= $secondDamage;
Лучше сделать у героя методы takeDamage($damage) и isAlive() Ты же вместо того чтобы положить относящийся к герою код в его класс, разимазываешь его равномерно по всей программе. В ООП объект это набор данных + методы для управления ими. А ты не хочешь делать методы, а исплоьзуешь объект как массив, зря.
Вообще, чтобы ты лучше прочуствовал эту концепцию, сделай свойства закрытыми, то есть не public, а private и используй методы для доступа к ним и их изменения.
Не очень хорошо конено что у тебя каждое действие обрабатывается в 2 местах:
> case '+':
> elseif($op == '+'){
неужели нельзя избавиться от повторов? Я уверен, что можно, попробуй.
Например ты можешь записать так:
если (текущий символ знак операции) {
выполнить операцию из $op;
...
если (текущий знак это равно) {
вывести результат и выйти;
}
...
}
В остальном, хорошо, считает верно.
> а еще файлы с классами,
app
> темплейты
templates, views
> css из бутсрапа
css, static
Бутстрап не надо разбирать на части. Кидай все как есть в папку css/bootstrap или static/bootstrap
Также, для классов есть 2 стандарта именования файлов (имя файла получается из имени класса), они помогут тебе когда ты захочешь использовать автозагрузку:
PSR 0 http://www.php-fig.org/psr/psr-0/ru/
PSR 4 http://www.php-fig.org/psr/psr-4/ru/
> Может вопрос глупый, но меня немного стопорнул.
Вопрос очень правильный. Файлы и папки надо называть правильно,а не как попало.
>>438556
> ременный каталог называй 1
Не 1, а tmp
> файл с паролями htpasswd
.htpasswd это пароли Апача.
> файл с паролями к базам данных - config.php.old или даже index.php.old
Бред какой-то если честно
>>438569
Выводишь что-то до того как поставить куку, а отпарвлять и заголовки и ставить куки, если начался вывод, уже нельзя.
>>438669
Достатоно не ставить закрывающий тег и проблем не будет, и перехватывать тоже ничего не надо будет.
>>438639
Пустой метод как и любая функция без команды return возвращает null: http://php.net/manual/ru/functions.returning-values.php
> а еще файлы с классами,
app
> темплейты
templates, views
> css из бутсрапа
css, static
Бутстрап не надо разбирать на части. Кидай все как есть в папку css/bootstrap или static/bootstrap
Также, для классов есть 2 стандарта именования файлов (имя файла получается из имени класса), они помогут тебе когда ты захочешь использовать автозагрузку:
PSR 0 http://www.php-fig.org/psr/psr-0/ru/
PSR 4 http://www.php-fig.org/psr/psr-4/ru/
> Может вопрос глупый, но меня немного стопорнул.
Вопрос очень правильный. Файлы и папки надо называть правильно,а не как попало.
>>438556
> ременный каталог называй 1
Не 1, а tmp
> файл с паролями htpasswd
.htpasswd это пароли Апача.
> файл с паролями к базам данных - config.php.old или даже index.php.old
Бред какой-то если честно
>>438569
Выводишь что-то до того как поставить куку, а отпарвлять и заголовки и ставить куки, если начался вывод, уже нельзя.
>>438669
Достатоно не ставить закрывающий тег и проблем не будет, и перехватывать тоже ничего не надо будет.
>>438639
Пустой метод как и любая функция без команды return возвращает null: http://php.net/manual/ru/functions.returning-values.php
> Чем чревато создание шаблонизатора
головной болью. Прочитай пункт 6 из статьи: http://habrahabr.ru/post/230737/ и откажись от этой идеи. Велосипедистов никто не любит, имей в виду. Исплоьзуй twig например.
В частности в твоем шаблонизаторе нельзя делать циклы, нет экранирования данных от XSS (урок по XSS: https://gist.github.com/anonymous/52adda0113428b274c64 ) и вооще тот кто потом будет читать твой код захочет тебя убить наверно за такое решение.
> То есть, какой бы не был php-скрипт, все вычисления, связь с базой данных, и прочее происходит через отдельный класс, и можно сделать так, что всё отображение производится через единственный index.php а все вычисления и связь с БД через core.php. Какие здесь подводные камни?
лучше бы ты испльзовал фреймворк или микрофреймворк. Вообще, пока из твоего описания проблем не вижу.
>>438675
Дело не в тормознутости (не факт что твой вариант тормозить будет). Почитай описание того же шаблониазтора twig и почитай какие там возможности и сравни со своим. Тебе придется писать более громоздкий и неудобный код в шаблоне и нельзя делать if, циклы и прочее. Как вообще без if и циклов ты собрался писать шаблоны?
Более того в php уже встроен шаблонизатор, лучше чем твой.
Советую использовать либо twig либо встроенный в php шаблонизатор, как описано тут: http://www.phpinfo.su/articles/practice/shablony_v_php.html
> Не хотел вставлять php-код в html-шаблоны из-за безопасности, вдруг кто-то сможет каким-то образом включить свой код и творить всё что угодно.
если ты не используешь eval и его братьев (create_function, assert) то ничего не будет. А вот XSS можно пропутсить, но если почитаешь мой урок то научишься от нее защищаться.
>>438676
А зачем ob_get... если без них будет так же? Более того, у тебя нет обработки исключений — при исключении ob_start никогда не отключится. такие вещи надо заворачивать в try/catch
path to tmplate тоже стоит передавать через аргументы.
>>438735
iconv
>>438830
Ладно, пусть так будет, хотя мне хак с font-size не особо нравится. Хорошие варианты по моему это вариант с комментарием и незакрытые теги. Главное чтобы ты знал про эту особенность CSS.
>>438846
А зачем? Пока юзер не нажал на кнопку он может все 10 раз поменять и отредактирвоать.
>>438852
Это плохая идея так как форма не будет отправляться по нажатию Enter. Надо исплоьзовать событие submit и предотвращать действие по умолчанию в обработчике (preventDefault/returnValue = false).
> если нужно знать результат отправки на .onreadystatechange указываешь колбек функцию
Это надо делать в любом случае чтобы обрабатывать ошибки отправки, блокировать кнопку на время запроса и показывать индикатор отправки. Если ты делаешь аякс то ты должен делать защиту от двойно отправки, обработку ошибок и индикатор иначе это будет кривая индусская поделка, которая постоянно будет ломаться и путать пользователя.
Ну и с аякс удобно работать через библиотеки, например jQuery.
>>438861
А как ты поймешь что оно заполнено и что пользователь ничего не будет менять? по моему это неудачная идея.
А так, уход из поля это событие blur, если ты его не знаешь то изучи какие вообще события есть:
https://developer.mozilla.org/en-US/docs/Web/Events (англ, подробно)
http://javascript.ru/tutorial/events
>>438860
Код по моему с ошибкой. Ты после битвы не восстанавливаешь состояние героев, в частности здоровье. Правильным решением будет клонировать героев и драться каждый раз новыми клонами (мануал: http://php.net/manual/ru/language.oop5.cloning.php ).
path to tmplate тоже стоит передавать через аргументы.
>>438735
iconv
>>438830
Ладно, пусть так будет, хотя мне хак с font-size не особо нравится. Хорошие варианты по моему это вариант с комментарием и незакрытые теги. Главное чтобы ты знал про эту особенность CSS.
>>438846
А зачем? Пока юзер не нажал на кнопку он может все 10 раз поменять и отредактирвоать.
>>438852
Это плохая идея так как форма не будет отправляться по нажатию Enter. Надо исплоьзовать событие submit и предотвращать действие по умолчанию в обработчике (preventDefault/returnValue = false).
> если нужно знать результат отправки на .onreadystatechange указываешь колбек функцию
Это надо делать в любом случае чтобы обрабатывать ошибки отправки, блокировать кнопку на время запроса и показывать индикатор отправки. Если ты делаешь аякс то ты должен делать защиту от двойно отправки, обработку ошибок и индикатор иначе это будет кривая индусская поделка, которая постоянно будет ломаться и путать пользователя.
Ну и с аякс удобно работать через библиотеки, например jQuery.
>>438861
А как ты поймешь что оно заполнено и что пользователь ничего не будет менять? по моему это неудачная идея.
А так, уход из поля это событие blur, если ты его не знаешь то изучи какие вообще события есть:
https://developer.mozilla.org/en-US/docs/Web/Events (англ, подробно)
http://javascript.ru/tutorial/events
>>438860
Код по моему с ошибкой. Ты после битвы не восстанавливаешь состояние героев, в частности здоровье. Правильным решением будет клонировать героев и драться каждый раз новыми клонами (мануал: http://php.net/manual/ru/language.oop5.cloning.php ).
> то как правильнее описать класс, элементом класса будет каждое поле формы?
Ты по моему не совсем правильно мыслишь. Ты думаешь что главное это форма и все строится вокруг нее. Но это не так. Главное — это модель, то есть сущность-студент, а форма это лишь способ изменять знаения его полей, и не обязательно едиснтвенный. Потому ты не должен делать класс представляюшщй форму с полями, а должен делать класс представляющий информацию о студенте.
> class student {
> public $name;
> public $lastname;
Вполне подойдет, но имя класса надо писать с большой буквы.
> Как лучше сделать возможность редактирования, когда я писал в обычном процедурном стиле это задание я использовал в случае правильно записи в базу данных такой код
Есть стандартный алгоритм работы с формой на все случаи жизни:
------------
$values = значения по умолчанию (пустые);
$errors = пустой массив;
Если (форма отправлена через POST) {
Переносим значения полей из POST в $values;
Если (все заполнено верно) {
Делаем требуемое действие (например вставляем запись в БД);
Редиректим куда-нибудь;
Выходим;
}
Кладем ошибки в $errors;
}
Выводим форму($values, $errors);
----------
В твоем случае удобно в качестве $values использовать объект класса Student.
Для сохранения объекта-студента в базу удобно использовать класс-маппер как описано тут: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
Сам же студент ничего про базу данных знать не должен. При таком подходе каждый занимается своим делом и код не спутан.
> Потом по вот этому $_SESSION["id"] для записи в которой такой же id выводил ссылку по которой можно пройти на редактирование данных. Но что то подсказывает мне этот метод не правильный.
Неактивные в течение 20-30 минут сессии удаляются. Сессия это временное хранилище. Так что да, используй тут лучше куки для которых мы можем выставить срок хранения. например, можно генерировать каждому студенту при регистрации длинный уникальный код, записывать его в куки и его же исплоьзовать для аутентификации.
>>438896
Лучше наверно поддержку спросить.
> то как правильнее описать класс, элементом класса будет каждое поле формы?
Ты по моему не совсем правильно мыслишь. Ты думаешь что главное это форма и все строится вокруг нее. Но это не так. Главное — это модель, то есть сущность-студент, а форма это лишь способ изменять знаения его полей, и не обязательно едиснтвенный. Потому ты не должен делать класс представляюшщй форму с полями, а должен делать класс представляющий информацию о студенте.
> class student {
> public $name;
> public $lastname;
Вполне подойдет, но имя класса надо писать с большой буквы.
> Как лучше сделать возможность редактирования, когда я писал в обычном процедурном стиле это задание я использовал в случае правильно записи в базу данных такой код
Есть стандартный алгоритм работы с формой на все случаи жизни:
------------
$values = значения по умолчанию (пустые);
$errors = пустой массив;
Если (форма отправлена через POST) {
Переносим значения полей из POST в $values;
Если (все заполнено верно) {
Делаем требуемое действие (например вставляем запись в БД);
Редиректим куда-нибудь;
Выходим;
}
Кладем ошибки в $errors;
}
Выводим форму($values, $errors);
----------
В твоем случае удобно в качестве $values использовать объект класса Student.
Для сохранения объекта-студента в базу удобно использовать класс-маппер как описано тут: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
Сам же студент ничего про базу данных знать не должен. При таком подходе каждый занимается своим делом и код не спутан.
> Потом по вот этому $_SESSION["id"] для записи в которой такой же id выводил ссылку по которой можно пройти на редактирование данных. Но что то подсказывает мне этот метод не правильный.
Неактивные в течение 20-30 минут сессии удаляются. Сессия это временное хранилище. Так что да, используй тут лучше куки для которых мы можем выставить срок хранения. например, можно генерировать каждому студенту при регистрации длинный уникальный код, записывать его в куки и его же исплоьзовать для аутентификации.
>>438896
Лучше наверно поддержку спросить.
Не считается.
> как прочитать его с помощью js?
Тебе надо почитать учебник для начала: http://learn.javascript.ru/form-elements
>>438931
Можно настроить дропбокс папку на 1 уровень выше чем папка сервера наверно. Либо сделать git репозиторий в папке дропбокса и пушить в него периодически.
>>438987
На гитхаб. Чтобы им пользоватьяс, надо освоить гит, есть отличная книга: http://git-scm.com/book/ru/v2
Если что то непонятно задавай вопросы.
Если не работал с командной строкой, прочти мой урок: https://gist.github.com/codedokode/10539568
Пока не освоил гит, файлы можно выложить сюда gist.github.com, рабоатет перетаскивание файлов с рабочего стола.
Чтобы работало, тебе надо найти бесплатный хостинг и выложить свой php код туда. Вот список хостингов: http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=free+php+hosting
западные хостинги бывают без рекламы, наши обычно с рекламой.
Например www.000webhost.com без рекламы.
Не считается.
> как прочитать его с помощью js?
Тебе надо почитать учебник для начала: http://learn.javascript.ru/form-elements
>>438931
Можно настроить дропбокс папку на 1 уровень выше чем папка сервера наверно. Либо сделать git репозиторий в папке дропбокса и пушить в него периодически.
>>438987
На гитхаб. Чтобы им пользоватьяс, надо освоить гит, есть отличная книга: http://git-scm.com/book/ru/v2
Если что то непонятно задавай вопросы.
Если не работал с командной строкой, прочти мой урок: https://gist.github.com/codedokode/10539568
Пока не освоил гит, файлы можно выложить сюда gist.github.com, рабоатет перетаскивание файлов с рабочего стола.
Чтобы работало, тебе надо найти бесплатный хостинг и выложить свой php код туда. Вот список хостингов: http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=free+php+hosting
западные хостинги бывают без рекламы, наши обычно с рекламой.
Например www.000webhost.com без рекламы.
Дамп базы данных в формате SQL не забудь приложить иначе я не смогу запустить твое приложение у себя.
>>439003
> помощь мне нужна даже в простейших заданиях.
Наш тред для этого и сделан
Решение почти верное, но нет проверки на ничью. Ведь может выпасть одинаковое число баллов.
exit во втором if лишний, работать будет без него.
?> в конце можно и нужно не писать
>>439004
Почему, codepad вполне нормальный, дизайн у него лучше чем ideone, хотя там по моему чего-то не хватает из расширений.
>>439005
if принято писать с маленькой буквы (с большой пишут константы и имена классов, что это такое ты потом узнаешь). exit в строке 26 лишний, можно без него. Нет проверки на ничью.
>>439011
Команды в скрипте выполняются по очереди, сверху вниз, только один раз. Чтобы они закольцевались, надо сделать цикл, об этом ты узнаешь в следующих уроках.
>>439024
> что бы можно было ввести "iv 49"
> и две подстроки искались бы отдельно во всех столбцах?
Можно разбаваить фразу процентами:
'%iv%49%'
И искать в строке склеееной из всех колонок:
WHERE CONCAT(name, ' ', score) LIKE ?
Но это не найдет слова если они идут в другом порядке (49 iv). Чтобы искать в любом порядке, нужны более сложные подходы, например full text search :
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html (англ)
http://www.mysql.ru/docs/man/Fulltext_Search.html (рус, кратко)
или внешние поисковые движки вроде sphinx: https://gist.github.com/codedokode/10539366
В этой задаче достаточно использовать что-нибудь на основе LIKE но если тыхочешь освоить еще и sphinx то я не против.
>>439049
> как правильно делать разлогинивание пользователя через сессии? Не просто же ансетать все переменные которые ты клал в этот массив во время логина?
Почему, unset вполне пойдет, а также там есть session_destroy для большей надежности.
> Вот при удачном логине я начинаю сессию и кладу в массив $_SESSION два элемента.
сессия удаляется при 20-30 минутах неактивности. Это неудобно и тебе придется дополнительно что-то класть в куки дял автоматического перезалогинвания. Сессия не постоянное, а временное хранилище.
> $login = mysqli_real_escape_string($link, $_POST['username']);
Научился бы уже плейсхолдерами пользоваться: http://php.net/manual/ru/mysqli.quickstart.prepared-statements.php
Ну и лучше исплоьзовать не процедурную, а ООП-версию mysqli, так проще будет PDO и другие библиотеки потом освоить.
>>439050
задавай вопросы. Это тред для начинающих.
>>439054
Все верно, только ?> в конце ставить не стоит.
Дамп базы данных в формате SQL не забудь приложить иначе я не смогу запустить твое приложение у себя.
>>439003
> помощь мне нужна даже в простейших заданиях.
Наш тред для этого и сделан
Решение почти верное, но нет проверки на ничью. Ведь может выпасть одинаковое число баллов.
exit во втором if лишний, работать будет без него.
?> в конце можно и нужно не писать
>>439004
Почему, codepad вполне нормальный, дизайн у него лучше чем ideone, хотя там по моему чего-то не хватает из расширений.
>>439005
if принято писать с маленькой буквы (с большой пишут константы и имена классов, что это такое ты потом узнаешь). exit в строке 26 лишний, можно без него. Нет проверки на ничью.
>>439011
Команды в скрипте выполняются по очереди, сверху вниз, только один раз. Чтобы они закольцевались, надо сделать цикл, об этом ты узнаешь в следующих уроках.
>>439024
> что бы можно было ввести "iv 49"
> и две подстроки искались бы отдельно во всех столбцах?
Можно разбаваить фразу процентами:
'%iv%49%'
И искать в строке склеееной из всех колонок:
WHERE CONCAT(name, ' ', score) LIKE ?
Но это не найдет слова если они идут в другом порядке (49 iv). Чтобы искать в любом порядке, нужны более сложные подходы, например full text search :
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html (англ)
http://www.mysql.ru/docs/man/Fulltext_Search.html (рус, кратко)
или внешние поисковые движки вроде sphinx: https://gist.github.com/codedokode/10539366
В этой задаче достаточно использовать что-нибудь на основе LIKE но если тыхочешь освоить еще и sphinx то я не против.
>>439049
> как правильно делать разлогинивание пользователя через сессии? Не просто же ансетать все переменные которые ты клал в этот массив во время логина?
Почему, unset вполне пойдет, а также там есть session_destroy для большей надежности.
> Вот при удачном логине я начинаю сессию и кладу в массив $_SESSION два элемента.
сессия удаляется при 20-30 минутах неактивности. Это неудобно и тебе придется дополнительно что-то класть в куки дял автоматического перезалогинвания. Сессия не постоянное, а временное хранилище.
> $login = mysqli_real_escape_string($link, $_POST['username']);
Научился бы уже плейсхолдерами пользоваться: http://php.net/manual/ru/mysqli.quickstart.prepared-statements.php
Ну и лучше исплоьзовать не процедурную, а ООП-версию mysqli, так проще будет PDO и другие библиотеки потом освоить.
>>439050
задавай вопросы. Это тред для начинающих.
>>439054
Все верно, только ?> в конце ставить не стоит.
Не знаю. Можешь написать задачу, а я подскажу как ее разбить. А вообще, это умение приходит с опытом, смотри код правильно написанных библиотек, например Symfony 2, читай книги про паттерны (Фаулер паттерны проектирования корпоративных приложений). В большиснтве случае решение уже есть и не надо ничего придумывать.
>Почему, unset вполне пойдет, а также там есть session_destroy для большей надежности.
Вот так вот сделал logout.php, на который ссылка ведет при клике на свой ник в index.php, в общем всё как на форумах
http://ideone.com/9kkdFG
Правильно? Сначала я проверял условием
if(isset($_SESSION['user_login'])){
А вот тут ансетал элементы
}
но потом подглядел вот такой способ на хабре.
>сессия удаляется при 20-30 минутах неактивности. Это неудобно и тебе придется дополнительно что-то класть в куки дял автоматического перезалогинвания. Сессия не постоянное, а временное хранилище.
Так что делать? Параллельно запускать соленые куки? Я прочитал вроде мануал по сессиям в новых версиях пхп5, и там сказано, что если на сервере включить нужные параметры, то всё будет ок, и механизм пхп сам будет слать куки, вот ссылка:
http://phpfaq.ru/sessions#use
>Научился бы уже плейсхолдерами пользоваться:
Ты меня верно вычислил на раз, прости пожалуйста, что я не следую твоим советам. Я на самом деле следую им, но у меня столько косяков и пробелов, что я не могу нормально всё это систематизировать. На самом деле я просто откладываю некоторые вещи постоянно, и мне очень стыдно. Обязательно выучу и покажу более годный вариант тебе.
Еще я такой человек, которому трудно учиться по книгам, мне нужен учитель, которого у меня нет, и поэтому я так медленно ползу, очень медленно.
> Вот так вот сделал logout.php,
куча лишнего кода
> setcookie(session_name(), session_id(), time()-606024);
session destroy и так это делает, зачем второй раз писать?
> echo "Тебе тут не место!
Скорее всего отобразится как кракозябры так как нет тега meta уакзывающего кодировку
> session_start( );
> if ( session_id() ) {
После session_start скорее всего session id всегда будет непустой и if становится бессмысленным
> Я прочитал вроде мануал по сессиям в новых версиях пхп5, и там сказано, что если на сервере включить нужные параметры, то всё будет ок, и механизм пхп сам будет слать куки, вот ссылка:
Ты понимаешь как работает сессия? данные сессии хранятся на сервере и подчищаются сборщиком мусора. В куках только id сессии. Соответственно еслим файл сессии удален на сервере то кука ничего не решает.
Делаются свои куки, например слогином и каким-нибудь хитрым кодом. Если сессия пустая то прежде чем считать пользователя разлогиненным мы проверяем есть ли куки и правильные ли в них значения и если да то создаем новую сессию и залогиниваем незаметно для пользоваетеля. Погугли, как работает галочка «запомнить меня»
И разумеется для этого наверняка есть либо библиотеки либо опции в фреймворках.
Для авторизации в куках можно хранить логин + хеш пароля или хеш от смеси пароль + какой-нибудь код. Например вконтакте раньше в куках хранил id и хеш от пароля.
Можно хранить в куках не связанный с паролем код, например просто длинный случайный код. В любом случае в куках должна быть информация идентифицирующая пользователя (кто это) и подтверждающая что это настоящий пользвоаетль, а не пытающийся притвориться им злоумышленник.
Некоторые вообще отказываются от сессий и используют только куки. Проблемы удаления сессий в этом случае нет.
Вообще плохо что ты сам изобртаешь систему авторизации. С твоим подходом она скорее всего окажется дырявая и ненадежная. Надо либо прочитать подробно о том как такие вещи делаются либо использовать готовую (какую? не знаю). Ну например если бы ты использовал фреймворки вродк Yii2 или Symfony 2, там уже все это реализовано.
Вот тут большой гайд на английском http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication
Там есть раздел
> How To Remain Logged In - The Infamous "Remember Me" Checkbox
Я еще хочу найти информацию на русском но честно говоря половина ссылок на эту тему ведут на какие-то быдлокодерские форумы, которые я не готов давать в качестве образца.
Вот тут еще что-то нашел: http://david-m.livejournal.com/1267236.html
Вот переделал по мере возможностей учитывая критику. Куки сюда сейчас впаивать не буду, с ними я разбирался в другой задаче, где солил их и проверял через функцию, сейчас я просто разбираюсь с сессиями.
>>439215
Да, спасибо, я не пытаюсь изобрести особо велосипед, я просто пытаюсь научиться использовать сессии. Ну и попутно выполняю учебное задание так сказать.
И кто из вас ОП? Спасибо за подсказки.
>Я еще хочу найти информацию на русском но честно говоря половина ссылок на эту тему ведут на какие-то быдлокодерские форумы, которые я не готов давать в качестве образца.
Я брал инфу отсюда:
http://phpfaq.ru/sessions#use
http://www.softtime.ru/bookphp/gl8_1.php
http://habrahabr.ru/post/182352/
По идее начинать стоит с мануала, но в мануале php тема освещена плохо: http://php.net/manual/ru/book.session.php
тут вроде нормальное описание
> Учебник по PHP 4
Ой-ой, какой старый, хотя про сессии информация в принципе не устарела
Это очень странная статья, там даже в комментах указывают. Этот код
> Контроль отсутствия активности пользователя встроенными средствами PHP
> ini_set('session.gc_maxlifetime', $sessionLifetime);
Скорее всего нерабочий, так как очистка сессий может выполняться крон-скриптом как это делается в дебиане и ini set никак на него не влияет.
В общем, статья плохая и содержит какие-то странные велосипеды.
>>439218
> И кто из вас ОП?
Оба поста мои
>>439220
> <!DOCTYPE html>
> session_start( );
Это не будет работать. нельзя ставить куки после того как начался вывод.
К тому же смешивать в одном файле html и php код плохая идея: http://www.phpinfo.su/articles/practice/shablony_v_php.html
По идее начинать стоит с мануала, но в мануале php тема освещена плохо: http://php.net/manual/ru/book.session.php
тут вроде нормальное описание
> Учебник по PHP 4
Ой-ой, какой старый, хотя про сессии информация в принципе не устарела
Это очень странная статья, там даже в комментах указывают. Этот код
> Контроль отсутствия активности пользователя встроенными средствами PHP
> ini_set('session.gc_maxlifetime', $sessionLifetime);
Скорее всего нерабочий, так как очистка сессий может выполняться крон-скриптом как это делается в дебиане и ini set никак на него не влияет.
В общем, статья плохая и содержит какие-то странные велосипеды.
>>439218
> И кто из вас ОП?
Оба поста мои
>>439220
> <!DOCTYPE html>
> session_start( );
Это не будет работать. нельзя ставить куки после того как начался вывод.
К тому же смешивать в одном файле html и php код плохая идея: http://www.phpinfo.su/articles/practice/shablony_v_php.html
Кстати header тоже нельзя делать после того как начал вывод. Потому что заголовки должны идти до тела HTTP-ответа.
https://github.com/Purplepeak/TestHub
ОП, посмотри пожалуйста тестхаб, когда время будет. В основном хочется услышать мнение по поводу кода относящегося к составлению и прохождению теста.
>> <!DOCTYPE html>
> session_start( );
>Это не будет работать. нельзя ставить куки после того как начался вывод.
Ну а как мне тогда указать кодировку не приплетая html? И при этом не делая отдельный шаблон под такую мелочь? Вместо обращения к юзеру сразу его релокейтить?
Ок, завтра может или послезавтра, так как у тебя там много всего.
>>439228
Можно попробовать переставить куски кода местами чтобы header делался до вывода html
> И при этом не делая отдельный шаблон под такую мелочь?
Это по моему не проблема
> Вместо обращения к юзеру сразу его релокейтить?
Можно
А в чем проблема? Страница с вопросом это же обычная форма, а сохранить/далее/назад это обычные submit кнопки. По моему так элементарно все делается. Определить какая кнопка нажата легко если у них разные имена так как в POST посылается только нажатая кнопка.
Или я что-то не понял?
С этим-то я разобрался. Я забил на это дело, когда писал отображение ошибок валидации и кнопку "пропустить". К сожалению, сейчас не опишу проблему конкретно, код писался довольно давно.
ИТТ мы будем говнокодить на самом поганом и в то же время самом популярном языке для веб-разработки на стороне сервера. Юзаем LAMP или WAMP стек, по умолчанию.
Essential Links
Официальный сайт:
http://php.net
Вики-ресурсы о сабже:
http://en.wikipedia.org/wiki/Php
http://ru.wikipedia.org/wiki/Php
http://lurkmore.to/PHP
PHP – The Right Way (лучшие практики)
http://phptherightway.com/
The League of Extraordinary Packages is a group of developers who have banded together to build solid, well tested PHP packages using modern coding standards.
http://thephpleague.com/
Russian-language resources
http://php.net/manual/ru/ – руководство по PHP на русском. Включая FAQ.
http://php.ru – русскоязычное сообщество и форум.
http://phpclub.ru – еще одно быдлокодерское сообщество и форум.
http://softtime.ru/bookphp/gl8_1.php – учебник по PHP 4 – старый конечно, но как справочник функций с примерами может пригодиться.
http://ruseller.com/ – коллекция относительно качественных материалов для веб-мастеров.
Books
Уже порядком устаревшие, но тем не менее культовые обучающие книги по PHP для новичков:
1) PHP 5 для чайников – Джанет Валейд (2005) [Диалектика]
2) PHP5 в подлиннике (2-е издание) – Котеров, Костарев (2008) [bhv]
И сотни других.
Костыли для PHP
Разработка многозадачных приложений на PHP5 (2008)
http://ibm.com/developerworks/ru/library/os-php-multitask/
Evolving PHP without Waiting for New Versions (2013)
В статье автор приводит большой список возможностей, которых не хватает в PHP (26 пунктов). Для каждой такой возможности приводит ссылки на существующие реализации.
http://phpclasses.org/blog/post/203-26-Ways-to-Show-that-PHP-Can-Be-Better-Than-PHP.html
Libs, classes
Крупный агрегатор PHP-классов, библиотек и прочего добра.
http://phpclasses.org/browse/
Список полезных PHP классов и библиотек (2009)
http://habrahabr.ru/post/70808/
Awesome PHP – огромный список отличных библиотек и утилит, а также ресурсов по PHP на все случаи жизни. Есть также awesome-python и awesome-ruby.
https://github.com/ziadoz/awesome-php
Pear
Ныне мертвый стандартизованный набор библиотек PEAR (PHP Extension and Application Repository).
http://ru.wikipedia.org/wiki/PEAR
Composer
Dependency Manager for PHP.
https://getcomposer.org/
ИТТ мы будем говнокодить на самом поганом и в то же время самом популярном языке для веб-разработки на стороне сервера. Юзаем LAMP или WAMP стек, по умолчанию.
Essential Links
Официальный сайт:
http://php.net
Вики-ресурсы о сабже:
http://en.wikipedia.org/wiki/Php
http://ru.wikipedia.org/wiki/Php
http://lurkmore.to/PHP
PHP – The Right Way (лучшие практики)
http://phptherightway.com/
The League of Extraordinary Packages is a group of developers who have banded together to build solid, well tested PHP packages using modern coding standards.
http://thephpleague.com/
Russian-language resources
http://php.net/manual/ru/ – руководство по PHP на русском. Включая FAQ.
http://php.ru – русскоязычное сообщество и форум.
http://phpclub.ru – еще одно быдлокодерское сообщество и форум.
http://softtime.ru/bookphp/gl8_1.php – учебник по PHP 4 – старый конечно, но как справочник функций с примерами может пригодиться.
http://ruseller.com/ – коллекция относительно качественных материалов для веб-мастеров.
Books
Уже порядком устаревшие, но тем не менее культовые обучающие книги по PHP для новичков:
1) PHP 5 для чайников – Джанет Валейд (2005) [Диалектика]
2) PHP5 в подлиннике (2-е издание) – Котеров, Костарев (2008) [bhv]
И сотни других.
Костыли для PHP
Разработка многозадачных приложений на PHP5 (2008)
http://ibm.com/developerworks/ru/library/os-php-multitask/
Evolving PHP without Waiting for New Versions (2013)
В статье автор приводит большой список возможностей, которых не хватает в PHP (26 пунктов). Для каждой такой возможности приводит ссылки на существующие реализации.
http://phpclasses.org/blog/post/203-26-Ways-to-Show-that-PHP-Can-Be-Better-Than-PHP.html
Libs, classes
Крупный агрегатор PHP-классов, библиотек и прочего добра.
http://phpclasses.org/browse/
Список полезных PHP классов и библиотек (2009)
http://habrahabr.ru/post/70808/
Awesome PHP – огромный список отличных библиотек и утилит, а также ресурсов по PHP на все случаи жизни. Есть также awesome-python и awesome-ruby.
https://github.com/ziadoz/awesome-php
Pear
Ныне мертвый стандартизованный набор библиотек PEAR (PHP Extension and Application Repository).
http://ru.wikipedia.org/wiki/PEAR
Composer
Dependency Manager for PHP.
https://getcomposer.org/
http://arhivach.org/thread/65094/
Начнём с очевидного.
Половина ссылок устаревшая, половина бесполезная, часть полезные. Ты сам-то их проверял или насобирал не проверяя?
сменил с помощью ALTER TABLE users ENGINE=MyISAM;
и написало что всё ок, но таблицу создать по прежнему не могу.
блин, на INNODB сменил конечно же, вот пруф, сутки не спал уже просто. Надеюсь на вас, аноны.
Попробуй сначала создать таблицу без внешнего ключа, а потом отдельным ALTER TABLE добавить внешний ключ — что будет?
Также, проверь не ссылается ли кто на таблицу posts. Вот тут на SO написано http://stackoverflow.com/a/4061333 если ты понимаешь анлийский. Найти все внешние ключи можно как описано тут http://stackoverflow.com/a/201678 в таблице INFORMATION_SCHEMA.KEY_COLUMN_USAGE
Похапэ знаю так себе - тут задачи прошел до кошек-мышек(не включая). Пару исправлений осталось. По оф.мануалу проходился, но практики в тех же исключениях/сессиях и прочей лабуде не хватает, если честно. Руку там не набил.
ЖС-на самом примитивном уровне. Даже DOM так и не освоил. Это, в принципе подтянуть можно. Было бы. Если стоило бы.
SQL - простейшие запросы. Даже, блеать, не помню как бэкап сделать.
Верстка - периодически подглядываю в чит-щит. Временами не оче получается с позиционированием.
Время - неделя. Мухосранск. Готов работать за еду.
p.s. После прочтения своего поста, в принципе, понимаю, что смысла нет, дурака валять не стоит, а стоит пойти говно месить. Чего-таки скажете?
Сейчас попробую, а пока дропнул даже таблицу юзерс, что бы пересоздать её, потому что вот эту темку почитал http://stackoverflow.com/questions/2799021
Ну и собственно там написано что поле user_id должно быть идентично в обоих таблицах, ну и пара других ньюансов.
Ну попробовать можно, от тебя не убудет. Тут был один, устроился с еще меньшими знаниями, после задачки на банкомат устроился куда-то за еду. А потом уволился потому-что ехать до работы было долго, ЛОЛ, теперь плачет тут. Говорит буст охуенный по знаниям, когда работаешь, изучаешь все в два раза быстрее, чем сидя дома.
Собственно ничего не потеряешь если походишь по собеседованиям, я примерно твоего уровня, но мне что бы ходить по собеседованиям надо ехать в какой-то крупный город в моём 30К городе само собой нет никаких вакансий по ПХП, поэтому ещё месяца 3 а может и больше буду учить всё это дома, сейчас пока работаю копирайтером, поэтому деньги на элементарные вещи есть, можно не спешить. А если у тебя в городе есть то почему бы и не рискнуть?
Всё верно говоришь почти, но не уверен что прям с намного меньшими знаниями. Самые азы mysql + php / php + html я знал. НУ и на пхп задачи все в плоть до бонусных таки прорешал. Собственно я и сейчас тут сижу, восстанавливаю старые знания после месяца задротства в игоры и учусь новому. Поэтому >>439313 конечно пытайся бро, лучше начать за минималку работать, чем дома ебланить.
Таки создал эту херню, >>439314 >>439302 и тут я ссылался на несуществующую таблицу: user вместо users, а вот тут >>439250 так и не ясно в чем была проблема.
Да минималка-не минималка то пофиг. Они меня просто на хуй с порога не пошлют с такими знаниями?
Олсо, только в требованиях "джуниор-погромист" или и на просто вакансию "программиста" можно пойти проситься джуном?
Или вообще пойти по адресам офисов аки бомж - "приютите, люди добрыя!", лел.
> а вот тут >>439250 так и не ясно в чем была проблема.
Иногда создание ключа вместе с таблицей не работает. Если при этом в 2 этапа (создать таблицу а потом ключи) все работает то видимо это какой-то баг или особенность MySQL. Я сам сталкивался с ошибкой MySQL 150 и обычно разделение на 2 команды помогает.
Подробности о последней ошибке с внешними ключами можно увидеть командой SHOW ENGINE InnoDB STATUS \G (выполняется из под администратора, то есть root) в разделе LATEST FOREIGN KEY ERROR. \G нужна чтобы строчки не разрывало.
Попробуй запустить эту команду. Это конечно плохо что MySQL прямо не пишет в чем проблема.
надо чтобы сервер при отдаче файла добавлял заголовок
Content-Disposition: attachment
Сделать этоо можно например через .htaccess под Апачем, погугли.
Ты скорее запости свой код ибо переделывть там тебе придется процентов 90 чтобы соответсовать нашим строгим стандартам.
По поводу ошибки, попробуй поставить в скрипте-обработчике var_dump($_FILES) и посмотри что там приходит.
Кстати команда SHOW ENGINE еще выдает много полезных данных которые пригодятся например при тюнинге размеров разных областей памяти для максимальной производиетлньсноти. Она документирована тут:
http://dev.mysql.com/doc/refman/5.7/en/show-engine.html
http://dev.mysql.com/doc/refman/5.7/en/innodb-standard-monitor.html
Еще эта штука покаызвает причину последней проблемы с блокироваками (она проявляется только на высоконагруженных сайтах, но ты хоть будешь знать где искать причину).
Я просто запилил резюме джуниора на сайт по поиску работы и меня самого нашли. Но нужно все варианты пробовать, в том числе и тем писать у которых висит просто "прогроммист php" и спрашивать не нужен ли джун за еду. Стори о которой >>439318 упоминал возможно еще не уплыла, поищи в декабрьских тредах. Там картинки приложены к постам цветные, легко найти. А сейчас мне лень писать тоже самое, да и спать сильно хочется.
Это я ктому что сидя дома денег не поднимешь, а жрат охота все сильнее. Это просто пздц.
>>439375
Всё потому, что пхп не воспринимается как серьёзный язык для веб-дева. Все думают, что ты должен был учить его лет с 14 в школе или хотя бы в инсте, а годам к 20-23 ты должен был по идее всё это знать. Или у тебя должен быть бэкграунд, чтобы всё это выучить за пару месяцев, а не учить всё с нуля в 25. Да дело даже не в конкретных цифрах возраста, а в том, что ты поздно начал.
я пробовал. дропбокс, хорошо, но там лимит 2гб, а у меня проект 4. там картинки и разная поеботина, а если грузить сугубо код, то теряются пути к этим самым картинкам, так как ссылки относительные. но я нашел неплохую альтернативу - cubbies.
Сами файлы:
https://ideone.com/caGrwo
https://ideone.com/xzAvbb
Вместо буквы "я" записывается "СЏ". Пикрелейтед кодировки в моем опенсервере и phpсторме.
Пробовал менять кодировку с помощью:
iconv_set_encoding("output_encoding", "WINDOWS-1251");
iconv("UTF-8","windows-1251",$name);
в самом ajax файле, но по неясным причинам это не помогает.
Буду рад любой помощи, потому что нет больше моих сил.
Так пиздуй работать грузчиком или продавцом-консультантом. С хуя ли ты решил, что потратив месяц на чтение учебников ты уже стал специалистом и можешь приносить хоть какую-то пользу? Думаешь, кто-то будет тратить время и деньги на твое обучение?
ООП изучается в процессе изучения ООП-языка. Паттерны на начальном этапе нинужны. Какие еще заморочки?
Пидора ответ.
> на начальном
Это на котором учишь синтаксис? А когда начинаешь пердолить бложек или ресурс с богатой админкой/лк, паттерны тоже не нужны? И где всё это брать после начального этапа?
>А когда начинаешь пердолить бложек или ресурс с богатой админкой/лк, паттерны тоже не нужны?
Нинужны.
>И где всё это брать после начального этапа?
https://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F
Гуглишь конкретный паттерн, если из описания в вики не понятно.
Как узнать, что мне нужен конкретный паттерн и для чего, на каком этапе и т.д.?
>Как узнать, что мне нужен молоток и для чего, на каком этапе и т.д.?
>Как узнать, что я хочу какать и для чего, на каком этапе и т.д.?
Изучай MVC на примере любого фреймворка. Остальное используется редко и нужно понимать, для чего конкретно, а не просто впердоливать чтоб было.
$_FILES["filename"]["tmp_name"];
Когда загружаю обычное изображение в формате jpeg, png или ещё в каком-нибудь. В то время как картинки созданные мной в пейнте получают свой tmp_name, это может быть ошибка с браузером или с операционной системой? Или это нормально?
это нормально
ООП немного описан в учебнике из ОП-поста, а также в 2 книгах. Я вообще не знаю, где изучают ООП, наверно есть какая-то хорошая книга на эту тему, но я ее не читал.
Насчет паттернов, начинающему их тружно понять, так как у него мало опыта и он может просто не понять вообще о чем речь. Паттерны это способы решения типичных ситуаций, возникающих при разработке.
Самая известная (культовая?) книга про паттерны это книга Фаулера «Шаблоны корпоративных приложений» ( Patterns of Enterprise Application Architecture ). Фаулер (это чувтвуется по тексту) очень опытный и умный программист, видел большое число приложений и он пытается в книге обобщить какие есть варианты решения той или иной проблемы, какие преимущества и недостатки.
Ты можешь почитать книгу, но будь готов к тому, что ничего не поймешь. Книга ориентирована на опытных, а не начинающих программистов.
Также каталог паттернов с кратким описанием есть на сайте Фаулера http://martinfowler.com/eaaCatalog/ и часть из них в переводе тут http://design-pattern.ru/
Ну например ты хочешь сохранять объекты в БД. Вместо изобретения велосипеда ты можешь посмотреть на готовые паттерны вроде http://design-pattern.ru/patterns/data-mapper.html или http://design-pattern.ru/patterns/active-record.html и выбрать какой-то (мне нравится Data Mapper).
Если ты посмотришь, то увидишь что паттерны во многом связаны с ООП и работой с базой данных. Это потому, что большинство приложений использует ООП и работает с базой данных (капитан очевидность).
Учить паттерны начинающему бессмысленно, если он их не понимает. Если какая-то компания спрашивает знание паттернов у людей без опыта то это издеватеьство над здравым смыслом и скорее всего там эти паттерны толком никто не знает кроме какого-нибудь синглетона (кстати синглетон это скорее вредный паттерн).
Некоторые паттерны (и ООП с MVC) ты можешь изучить в ходе решения практических задач в нашем треде.
Если у тебя есть какие-то вопрсоы или что-то непонятно, задавай.
Ты можешь сделать то что я писал выше то есть поставить var_dump($_FILES); в начале скрипта и показать нам что он выводит? Твое описание к сожалению не позволяет установить причину проблемы.
>>439470
> Остальное используется редко
дело даже не в том что редко, а в том, что ты можешь этого не знать. Ты используешь Doctrine 2 например но не знаешь что она использует внутри паттерны Data Mapper, Identity Map, lazy Loading и другие (хотя конечно это плохо если не знаешь).
>>439453
> А когда начинаешь пердолить бложек или ресурс с богатой админкой/лк, паттерны тоже не нужны?
Такие вещи никто не пишет с нуля а берут фреймворк или CMS на худой конец и делают как там принято и как описано в документации.
> И где всё это брать после начального этапа?
У нас есть неплохие практические задаки которые учат писать простые приложения с базой данных, с ООП/MVC. Они в ОП посте есть.
>>439429
А зачем ты используешь win 1251? Странная идея конечно.
> когда через аякс передаю значение в файл, который должен его записать в бд, кирилица читается норм(вывожу через эхо, например) но вот в самой бд там закарлючки.
SET NAMES делаешь и если делаешь то какой?
Это читал?
http://phpfaq.ru/charset
http://www.tmanager.ru/russian/charset.html
http://fstrange.ru/coder/mysql/kodirovka-krakozyably.html
http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
Ты можешь сделать то что я писал выше то есть поставить var_dump($_FILES); в начале скрипта и показать нам что он выводит? Твое описание к сожалению не позволяет установить причину проблемы.
>>439470
> Остальное используется редко
дело даже не в том что редко, а в том, что ты можешь этого не знать. Ты используешь Doctrine 2 например но не знаешь что она использует внутри паттерны Data Mapper, Identity Map, lazy Loading и другие (хотя конечно это плохо если не знаешь).
>>439453
> А когда начинаешь пердолить бложек или ресурс с богатой админкой/лк, паттерны тоже не нужны?
Такие вещи никто не пишет с нуля а берут фреймворк или CMS на худой конец и делают как там принято и как описано в документации.
> И где всё это брать после начального этапа?
У нас есть неплохие практические задаки которые учат писать простые приложения с базой данных, с ООП/MVC. Они в ОП посте есть.
>>439429
А зачем ты используешь win 1251? Странная идея конечно.
> когда через аякс передаю значение в файл, который должен его записать в бд, кирилица читается норм(вывожу через эхо, например) но вот в самой бд там закарлючки.
SET NAMES делаешь и если делаешь то какой?
Это читал?
http://phpfaq.ru/charset
http://www.tmanager.ru/russian/charset.html
http://fstrange.ru/coder/mysql/kodirovka-krakozyably.html
http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
>есть неплохие практические задаки
Задачи есть, а как их решать не понятно, например. Откуда? Ведь есть только базовые уроки, документация, в которой куски кода, вырванные из контекста и всё. Откуда я могу узнать об ооп/mvc, если не знаю об их существовании. Советуют изучать по готовым фреймворкам, но как понять зачем это было сделано, вдруг это Вася какой-нибдуь очередной велосипед придумал. Ну и то же касается и других вещей.
Это не претензия к ОПу, если что, просто опытные программисты напридумывали каждый свой велосипед, объединились в группы, а как это понять и дойти до этого новичку не понятно.
Нет какого-то единства и конкретики. Подчеркну, что это со стороны новичка, а не со стороны того, кто в этом разбирается.
> iconv_set_encoding("output_encoding", "WINDOWS-1251");
Это тут не при чем (я сам не очень понимаю на что влияет эта настройка). ты не должен ставить наугад разные команды в надежде что все исправится, лучше разобарться в проблеме, это тебе потом пригодится.
> в самом ajax файле, но по неясным причинам это не помогает.
Потому что SET NAMES не делаешь и там какая-то другая кодировка для взаимодействия с БД исплоьзуется. Ты должен через SET NAMES сказть базе данных в какой кодировке ты передаешь и принимаешь от нее данные.
Ну и я удивлен что кто-то в 2015 использует win 1251.
>>439427
> а если грузить сугубо код, то теряются пути к этим самым картинкам, так как ссылки относительные
Странно конечно
>>439419
В разных компаниях разные требовния. Но от более взрослого кандидата наверно могут ждать больший набор знаний. Ведь молодого еще можно взять в надежде что он доучится, а взрослый наверно уже сам должен был к 30 годам все что нужно успеть выучить.
Я работая в одной компании слышал примерно такое: «люди после 25 у нас плохо уживаются».
>>439377
Если есть такая возможность ты бы мог устроиться парт тайм на какую то работу, а оставшиеся полдня учить php. Наш тред всегда готов помочь с обучением.
>>439375
Все зависит от компании. Где-то берут стажеров с минимальными знаниями, где-то требуется пилот шаттла.
Насчет знаний CMS/фрйемворков если компания маленькая то может быть предпочтительнее человек со знанием нужного продукта, который сразу войдет в курс дела.
Ну и с нынешней экономической ситуацией не стоит быть слишком разборчивым. денег будет меньше, нанимать будут меньше людей.
> iconv_set_encoding("output_encoding", "WINDOWS-1251");
Это тут не при чем (я сам не очень понимаю на что влияет эта настройка). ты не должен ставить наугад разные команды в надежде что все исправится, лучше разобарться в проблеме, это тебе потом пригодится.
> в самом ajax файле, но по неясным причинам это не помогает.
Потому что SET NAMES не делаешь и там какая-то другая кодировка для взаимодействия с БД исплоьзуется. Ты должен через SET NAMES сказть базе данных в какой кодировке ты передаешь и принимаешь от нее данные.
Ну и я удивлен что кто-то в 2015 использует win 1251.
>>439427
> а если грузить сугубо код, то теряются пути к этим самым картинкам, так как ссылки относительные
Странно конечно
>>439419
В разных компаниях разные требовния. Но от более взрослого кандидата наверно могут ждать больший набор знаний. Ведь молодого еще можно взять в надежде что он доучится, а взрослый наверно уже сам должен был к 30 годам все что нужно успеть выучить.
Я работая в одной компании слышал примерно такое: «люди после 25 у нас плохо уживаются».
>>439377
Если есть такая возможность ты бы мог устроиться парт тайм на какую то работу, а оставшиеся полдня учить php. Наш тред всегда готов помочь с обучением.
>>439375
Все зависит от компании. Где-то берут стажеров с минимальными знаниями, где-то требуется пилот шаттла.
Насчет знаний CMS/фрйемворков если компания маленькая то может быть предпочтительнее человек со знанием нужного продукта, который сразу войдет в курс дела.
Ну и с нынешней экономической ситуацией не стоит быть слишком разборчивым. денег будет меньше, нанимать будут меньше людей.
>>439491
> а как их решать не понятно, например.
Должны быть уроки которые этому учат, но их пока нет потому что ОП их не написал. Потому аноны идут, ищут какие-то уроки на других сайтах, делают, показывают решение, ну и половину примерно потом еще переделывают чтобы было правильно.
По идее там должны быть уроки про то как установить себе php/апач, как работает браузер и веб-сервер, протокол HTTP, язык HTML, про работу с формами в HTML/PHP, про базы данных и язык SQL, про работу с базой данных через PDO, про MVC, про Data Mapper (ну этот урок у меня написан: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a )
Сразу после учебника можно прочесть про работу с формами, например вот это для начала:
http://php.net/manual/ru/tutorial.php
Если ты не знаком с тем то такое HTML то выучи хотя бы основы, у нас есть ссылки и задачки для этого: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
Если ты не знаком с базами данных, то опять же у нас есть ссылки и задачки, выуи хотя бы основы: https://gist.github.com/codedokode/10539213
ну и если что-то еще непонятно, ты можешь задавать вопросы в треде.
> Откуда я могу узнать об ооп/mvc, если не знаю об их существовании.
Основы ООП же есть в учебнике, в последней главе. Читал? Также про ООП есть информация в книгах Зандстры и Шлосснейгла (в ОП посте).
MVC нету, но вся суть MVC в разделении кода на контроллеры, модель и view, можно нагуглить статьи на том же хабре.
> просто опытные программисты напридумывали каждый свой велосипед, объединились в группы, а как это понять и дойти до этого новичку не понятно.
Ты можешь дойти, если так хочешь, но это будет долго. Ведь писать фреймворки гораздо сложнее чем использовать готовый. Потому и используют готовые. а не пишут свои. Но если ты очень хочещь, ты можешь попробовать ,а я укажу где косяки и чем плох твой подход.
> Нет какого-то единства и конкретики
да, нету, потому что тут довольно большой объем работы и одному все эти уроки написать довольно сложно и требует много времени. Но с другой стороны, я вижу что другие аноны в итоге как-то справляются с задачами — значит все это можно где-то найти.
>>439491
> а как их решать не понятно, например.
Должны быть уроки которые этому учат, но их пока нет потому что ОП их не написал. Потому аноны идут, ищут какие-то уроки на других сайтах, делают, показывают решение, ну и половину примерно потом еще переделывают чтобы было правильно.
По идее там должны быть уроки про то как установить себе php/апач, как работает браузер и веб-сервер, протокол HTTP, язык HTML, про работу с формами в HTML/PHP, про базы данных и язык SQL, про работу с базой данных через PDO, про MVC, про Data Mapper (ну этот урок у меня написан: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a )
Сразу после учебника можно прочесть про работу с формами, например вот это для начала:
http://php.net/manual/ru/tutorial.php
Если ты не знаком с тем то такое HTML то выучи хотя бы основы, у нас есть ссылки и задачки для этого: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
Если ты не знаком с базами данных, то опять же у нас есть ссылки и задачки, выуи хотя бы основы: https://gist.github.com/codedokode/10539213
ну и если что-то еще непонятно, ты можешь задавать вопросы в треде.
> Откуда я могу узнать об ооп/mvc, если не знаю об их существовании.
Основы ООП же есть в учебнике, в последней главе. Читал? Также про ООП есть информация в книгах Зандстры и Шлосснейгла (в ОП посте).
MVC нету, но вся суть MVC в разделении кода на контроллеры, модель и view, можно нагуглить статьи на том же хабре.
> просто опытные программисты напридумывали каждый свой велосипед, объединились в группы, а как это понять и дойти до этого новичку не понятно.
Ты можешь дойти, если так хочешь, но это будет долго. Ведь писать фреймворки гораздо сложнее чем использовать готовый. Потому и используют готовые. а не пишут свои. Но если ты очень хочещь, ты можешь попробовать ,а я укажу где косяки и чем плох твой подход.
> Нет какого-то единства и конкретики
да, нету, потому что тут довольно большой объем работы и одному все эти уроки написать довольно сложно и требует много времени. Но с другой стороны, я вижу что другие аноны в итоге как-то справляются с задачами — значит все это можно где-то найти.
Стоит сделать класс представляющий файл, да. Это же важная сущность в программе, все вокруг них строится.
вызубрил ООП, щеголял пособеседованиям на джуна, неплохо отвечал, но понял его только когда начал проэкт ооп писать. Такие дела. Теория без практики хуита, выше анон верно сказал, что ооп учится в процессе. Для начала почитай в целом за него, потом напиши что-нибудь в стиле ооп и дело в шляпе, азы выучены.
Лучше газосварщиком сразу иди и работа непыльная и денег платють, да и в парашке всегда будет, что резать, если уж не варить.
Сажерс приклеился.
PHP, HTML, CSS, SQL, JS, JQuery, Git, Composer, WP\Magento\Drupal, ZF2\Yii\Symfony этого хватит.
Переделываю с нуля, начал с заполнения свойств класса Hero через форму пикрелейтед. Как на вид?
Выглядит норм, но если присмотреться, видны пара косяков в дизайне.
Во-первых, на кнопках текст упирается в край кнопки, ему там тесно — это некрасиво, надо чуть увеличить поля.
Сами кнопки можно сделать разными — кнопку «провести генерацию» сделать ярче чем «очистить данные», так как она основная.
Во-вторых, у тебя подпись к инпуту от него оторвана и прижата к соседнему инпуту выше. Это неправильно — подпись должна быть ближе к тому инпуту, к которому относится.
Сами поля ввода я бы сделал меньше по длине. Ведь в них будет вводиться всего 2-3 цифры — зачем такие длинные поля ввода?
пхп переменные мы называем $cameCase например.
А как называть html-переменные которые скажем потом пойду в $_POST[]? До этого они у меня были простыми очень, по типу text, name, и соответственно из поста я забирал $_POST['text'], $_POST['name']
А сейчас у меня переменная из 2х слов впервые появилась, как быть в этом случае?
Я нулевой в пыхе и мне надо для курсовой сделать интернет-магазин. С готового сайта проще разобраться и переделать под себя.
Выручайте. Пикрандом.
>Я нулевой в пыхе и мне надо для курсовой сделать интернет-магазин.
Хуя себе, как по мне, то скорее всего уже уровень диплома, если самому писать.
Но вообще наверное есть какие-то заготовки, и можно побыстренькому, хуяк-хуяк и только дизайн натянуть осталось и заполнить базу. Так что гугли эту хуйню.
На opencart любой бесплатный шаблон натяни и сдай, у нас большинство так и сделало. Охуенный "диплом", работы на один вечер.
Class 'Slim' not found
в чем может быть проблема?
Я думаю, стоит делать аналогично. Хотя бывает что их называют через почеркивание (student_name), но наверно лучше называть единообразно.
>>439656
Открой документацию: http://docs.slimframework.com/
Там есть 2 варианта, composer install и manual install. У тебя явно manual так что посмотри, ты там автозагрузчик забыл зарегистрировать.
Ну и наверно лучше бы сразу учиться композер использовать, а не вручную ставить. Статья:
http://habrahabr.ru/post/145946/
Там упоминается командная строка. Если ты не очень знаком с командной строкой то вот гайд: https://gist.github.com/codedokode/10539568
>>439666
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Проверить, работает ли вывод ошибок, можно запустив скрипт содержающий обращение к несуществующей переменной вроде echo $sdgasdad; и проверив, выведется ошибка или нет. Если все верно, то должна вывестись.
> включить нельзя.
через ini_set('display_errors', true) пробовал?
А вообще то там должны быть логи и ты можешь посмотреть причину ошибки в них. Так будет правильнее. Пользователям незачем видеть подрбности потому на смотрящих в итнетрнет серверах отображдение ошибок отключают.
А, еще ты неймспейс забыл прописать (команду use вверху).
Мануал: http://php.net/manual/ru/language.namespaces.php
И посмотри примеры в начале документации, там класс с именем неймспейса идет.
Уже сделал, теперь не пойму, как
из $app->get('/:id', function ($id){
что то получить
или вызвать в ней датамапер
Во-первых перемеенные можно получить через use как тут в 3 примере: http://php.net/manual/ru/functions.anonymous.php
Во-вторых, праивльнее будет сделать датамаппер синглтоном в слиме, как описано тут http://docs.slimframework.com/#DI-Overview в разделе Singleton resources и обращаться к нему через $app->fileMapper
> \t$app->get('/:id', function ($id){
> $mapper=$app->fileMapper;
Внутри функции перменная $app пр умолчанию не видна, так же как и созданные в функции переменные не видны снаружи (прочти мануал: http://php.net/manual/ru/language.variables.scope.php ). Ты должен сделать переменную app доступной с помощью use как описано тут http://php.net/manual/ru/functions.anonymous.php
>>439674
на локалхосте у меня ошибки включены, но их и нет. на удаленном php.ini изменить никак нельзя, в панели управления вроде как логи должны быть, но то ли отключены для бесплатных тарифов, то ли я найти не смог, написал в поддержку. пока ждал ответа начал перебирать, отключая по одной строчке. оказывается, нельзя создавать массив таким образом как у меня, то есть
$_SESSION=[a,b,c,d];
через array(a,b,c,d) все работает. версия пыхи, что ли. неслабый такой подводный камень, приходится теперь вылавливать на всех страничках.
Можешь перед этой штукой воткнуть
error_reporting(-1);
Еще я у тебя не вижу mysql_connect(...) перед тем как делать запросы в базу.
Далее я бы начал с простого, например после первого же твоего
var_dump($_POST);
У тебя условия такие, что может быть они просто не выполняются, поэтому ничего и не работает.
Далее может быть дело в том, что на удаленном сервере неподдерживаются функции mysql_... пропробуй переписать через mysqli_...
>Далее я бы начал с простого, например после первого же твоего
>var_dump($_POST);
Далее я бы начал с простого, например после первого же твоего условия на проверку $_POST я бы его сдампил
var_dump($_POST);
Пожалуйста пиши больше подробнстей?
В чем проявляется «не работает»?
Что выведет если поставить var_dump($_POST); перед 22 строкой?
при первом заходе на страницу с var_dump($_POST);
array(0) { }
и кнопка
при на нажатие на кнопку
404 Page Not Found
The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.
Visit the Home Page
array(0) { }
и кнопка
хотя урл же не меняется и роутер должен нормально стработать
А что по твоему должно быть? Так как для post ты не задал обработчик в Слиме то он выводит страницу 404. А после нее твой код срабатывает.
Надо сделать для обработки post роут в Слиме как тут описано: http://docs.slimframework.com/#POST-Routes
> хотя урл же не меняется и роутер должен нормально стработать
Роут созданный через get() как следует из его названия реагирует только на GET запросы.
$dt = timе;
Но дата не записывается, записывается 000-00-00, если через пхпмуадмин зайти и кликнуть по полю где это значение, то дата появляется. Вообще не понимаю что происходит, что это может быть?
> то они будут хранится в кодировке файла?
да
> Если у файла кодировка utf-8, то как мне отсортировать строки в натуральной сортировке без смены локали (это ведь жутко неудобно)?
Смена локали это плохая идея, плюс локаль работает только с 8 битными кодировками, а не с utf8 и тебе никак не поможет.
Во-первых, ты можешь отсортировать с помощью sort. Она сортирует не по правилам, а по кодам символов, но вдруг отсортирует как надо?
Если ты хоешь нормальное решение, то оно есть, это расширение Intl и класс Collator, вот мой урок на эту тему: https://gist.github.com/codedokode/ea09d0224a4df0c4442f
Там есть несколько методов для сортировки: http://php.net/manual/ru/collator.sort.php
Если нет возможности поставить расширение (что плохо) то можно поискать библиотеки реализующие аналогичный интерфейс, например http://symfony.com/doc/current/components/intl.html
>>439776
В Бд даты надо передавать в виде строки, а не числа. Вот формат: http://www.mysql.ru/docs/man/DATETIME.html
Преобразовать туда/обратно можно с помощью php функций strtotime() и date('Y-m-d H:i:s').
не удержался, когда несут бред,
>В Бд даты надо передавать в виде строки
никогда не слушай этих "умных", даты переводы в ЧИСЛО и передавай ТОЛЬКО число, и храни именно ЧИСЛО.
поиск среди чисел в 1000раз быстрей, занимаемое место ячейки бд всего 4 байта, индекс строится как бтрее в 100раз быстрей чем по строке datetime, легко получить лубую дату через date('str',time) и т.д.
Ты мерял или ты очередной диванный оптимизатор которые в нашем треде минимум раз в месяц отмечаются?
$app->get('/:id', function ($id) use ($mapper){ \t\t
\t\treturn $file=$mapper->showFilebyID($id);
});
Из $app->get вообще можно что то получить?
Мне нужно в хтмл использовать $file, но как её достать?
Поясни. Зачем тебе что то от туда вытаскивать?
Почему не можешь выводить шаблон? как в примере с Hello, world.
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
Ты делаешь неправильно. Вот посмотри на этот код: https://ideone.com/IRcAww
Ты вставляешь кусок html прямо после вызова фреймворка. Получается у тебя для любых страниц выводится один и тот же html? Все страницуы будут одинаковые?
Более того, плохо вообще в одном файле смешивать php код и html шаблон.
Фреймворк slim предоставляет микрошаблонизатор для решения этой проблемы. Фактически этот микрошаблонизатор просто подключает указанный php файл и передает в него переменные.
Почитай документацию (если ты не понимаешь английский хотя бы примеры кода посмотри и попробуй перевод через bing translate почитать: http://www.bing.com/translator/ - там часть текста понять можно).
Там есть раздел view: http://docs.slimframework.com/#View-Overview
Там есть пример кода где видно как используется метод $app->render('myTemplate.php' ....)
Ты должен использовать его если хочешь вывести страницу. Вызывается app->render обычно изнутри обработчика в $app->get().
А твой код в принципе нерабочий. Например вот это:
> header("Pragma: public");
не будет работать так как перед этим Слим выведет страницу 404.
Ну и с самими заголовками перебор, там большинство их них не нужны. Реально нужно только 2:
header("Content-Disposition: attachment");
header("Content-Type: image/jpeg"); // не jpg
Также в заголовках еще ошибки:
- в Content-Type надо указывать не расширение, а MIME-тип вроде image/jpeg. MIME типы регистриурет организация под названием IANA, так что это что-то вроде стандарта. Вот список MIME типов: 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
Учить его не надо, но хотя бы полистай, посмотри какие вообще типы бывают.
- не используй параметр filename в заголовке content-disposition. Для него не определена кодировка (точнее определено стандартом что нельзя использовать ничего кроме латиннциы) и разные бруаузеры воспринимают его по-разному.
Вот статьи про то, какие вообще заголовки бывают:
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields (англ)
https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%B7%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%BE%D0%B2_HTTP
Заголовки это часть протокола HTTP. Вот статья про сам протокол HTTP если ты его не очень знаешь:
http://scriptsite.ru/article/show/5/
Это был разбор кода. Теперь вернемся к твоему вопросу.
> Из $app->get вообще можно что то получить?
> Мне нужно в хтмл использовать $file, но как её достать?
Ты вызываешь app->render и передаешь туда все переменные, которые нужны.
Если есть еще какие-то вопросы по Слиму или вообще, уточняй.
Вообще, со Слимом твое приложение (точнее файл index.php) должен выглядеть примерно так:
подключение Слима;
// объявляем сервисы (синглтоны слима)
$app->container->singleton ....
$app->container->singleton ....
// задаем функции обработчики для разных видов запросов
$app->get ...
$app->get ...
$app->post ...
// запускаем приложение
$app->run( );
Если ты знаком с MVC то у нас фактически тут контроллеры пишутся внутри app->get и app->post. Напомню что app->get задает функию-обработчик для определенных GET запросов, а post для POST.
Ты делаешь неправильно. Вот посмотри на этот код: https://ideone.com/IRcAww
Ты вставляешь кусок html прямо после вызова фреймворка. Получается у тебя для любых страниц выводится один и тот же html? Все страницуы будут одинаковые?
Более того, плохо вообще в одном файле смешивать php код и html шаблон.
Фреймворк slim предоставляет микрошаблонизатор для решения этой проблемы. Фактически этот микрошаблонизатор просто подключает указанный php файл и передает в него переменные.
Почитай документацию (если ты не понимаешь английский хотя бы примеры кода посмотри и попробуй перевод через bing translate почитать: http://www.bing.com/translator/ - там часть текста понять можно).
Там есть раздел view: http://docs.slimframework.com/#View-Overview
Там есть пример кода где видно как используется метод $app->render('myTemplate.php' ....)
Ты должен использовать его если хочешь вывести страницу. Вызывается app->render обычно изнутри обработчика в $app->get().
А твой код в принципе нерабочий. Например вот это:
> header("Pragma: public");
не будет работать так как перед этим Слим выведет страницу 404.
Ну и с самими заголовками перебор, там большинство их них не нужны. Реально нужно только 2:
header("Content-Disposition: attachment");
header("Content-Type: image/jpeg"); // не jpg
Также в заголовках еще ошибки:
- в Content-Type надо указывать не расширение, а MIME-тип вроде image/jpeg. MIME типы регистриурет организация под названием IANA, так что это что-то вроде стандарта. Вот список MIME типов: 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
Учить его не надо, но хотя бы полистай, посмотри какие вообще типы бывают.
- не используй параметр filename в заголовке content-disposition. Для него не определена кодировка (точнее определено стандартом что нельзя использовать ничего кроме латиннциы) и разные бруаузеры воспринимают его по-разному.
Вот статьи про то, какие вообще заголовки бывают:
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields (англ)
https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%B7%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%BE%D0%B2_HTTP
Заголовки это часть протокола HTTP. Вот статья про сам протокол HTTP если ты его не очень знаешь:
http://scriptsite.ru/article/show/5/
Это был разбор кода. Теперь вернемся к твоему вопросу.
> Из $app->get вообще можно что то получить?
> Мне нужно в хтмл использовать $file, но как её достать?
Ты вызываешь app->render и передаешь туда все переменные, которые нужны.
Если есть еще какие-то вопросы по Слиму или вообще, уточняй.
Вообще, со Слимом твое приложение (точнее файл index.php) должен выглядеть примерно так:
подключение Слима;
// объявляем сервисы (синглтоны слима)
$app->container->singleton ....
$app->container->singleton ....
// задаем функции обработчики для разных видов запросов
$app->get ...
$app->get ...
$app->post ...
// запускаем приложение
$app->run( );
Если ты знаком с MVC то у нас фактически тут контроллеры пишутся внутри app->get и app->post. Напомню что app->get задает функию-обработчик для определенных GET запросов, а post для POST.
А еще, ты делал задание про студентов? Или NotBadCode это как раз ты? Я постараюсь сегодня его все же проверить.
>>439887
Да, это не круто. HTML код должен быть в шаблонах.
>>439878
Это был лишь пример на практике используется app->render.
>>439877
ссылкой c id поста в ней например, вида /posts/edit/123456
>>439847
Еще нехороший момент: зачем ты пишешь присваивание внутри return?
> return $file=$mapper->showFilebyID($id);
надо писать в 2 команды как
$file=$mapper->showFilebyID($id);
return $file;
Но если подумать то какой смысл создавать переменную file? Не логичнее ли сразу написать
return $mapper->showFilebyID($id);
Ты случайно не думаешь что в return $file = ... имя переменной file на что-то влияет? return просто возвращает значение, неважно как названа переменная (и есть ли там переменная вообще). Он возвраащет число, строку или что ты там ему передашь, а имя переменной не важно.
Ох, ты случайно не пропустил несколько глав в моем учебнике? Если бы ты эти ошибки в задачах делал я бы обязательно обратил внимание.
А еще, ты делал задание про студентов? Или NotBadCode это как раз ты? Я постараюсь сегодня его все же проверить.
>>439887
Да, это не круто. HTML код должен быть в шаблонах.
>>439878
Это был лишь пример на практике используется app->render.
>>439877
ссылкой c id поста в ней например, вида /posts/edit/123456
>>439847
Еще нехороший момент: зачем ты пишешь присваивание внутри return?
> return $file=$mapper->showFilebyID($id);
надо писать в 2 команды как
$file=$mapper->showFilebyID($id);
return $file;
Но если подумать то какой смысл создавать переменную file? Не логичнее ли сразу написать
return $mapper->showFilebyID($id);
Ты случайно не думаешь что в return $file = ... имя переменной file на что-то влияет? return просто возвращает значение, неважно как названа переменная (и есть ли там переменная вообще). Он возвраащет число, строку или что ты там ему передашь, а имя переменной не важно.
Ох, ты случайно не пропустил несколько глав в моем учебнике? Если бы ты эти ошибки в задачах делал я бы обязательно обратил внимание.
В неделю не многим более, чем за ночь берёт твоя машаша-шлюха.
Анон, я проверил твой код. Вообще, не так плохо дял начинающего (ты наверно читал мои замечания к коду других анонов?). Но много чего надо исправить.
Советы и замечания по коду.
https://github.com/NotBadCode/Students
> `place` int(2) NOT NULL,
> `sex` int(1) NOT NULL,
Тут лучше подойдет ENUM. Я например смотрю на SQL код и не могу понять что значит 0 или 1. И другой человек, который захочет разобрать твой код, тоже не поймет без анализа кода.
В сложных случаях в SQL ты можешь добавлять комментарии к колонкам или всей таблице. Эти комментарии сохраняются в базе и отображаются в программах для работы с БД. Используй их: http://stackoverflow.com/a/200033
> `groupnum` int(5) NOT NULL,
Лучше номер группы сделать строкой. А то как ты будешь сохранять номер 00010?
> `year` int(4) NOT NULL,
Есть тип YEAR и догадайся-ка, для чего он придуман?
Я вижу ты плохо знаешь типы данных. Почитай (учить наизусть не надо, но ответ на вопрос «в чем хранить дату» или «в чем хранить номер телефона» или «в чем хранить сумму с копейками» знать надо):
http://phpclub.ru/mysql/doc/column-types.html
http://artemfedorov.ru/etc/mysql/field-types/
Также, если в таблице некоторые колонки не должны иметь повторы, добавь к ним уникальный ключ (UNIQUE KEY).
> https://github.com/NotBadCode/Students/blob/master/index.php#L3
После <?php не надо добавлять отступ (убрать оступ в большинстве редакторов можно выделив все и нажав Shift + Tab)
Также, я советую поставить в редакторе настройку «заменять таб на 4 пробела», а то смотри как у тебя код расползся на гитхабе некрасиво.
> $id=$_COOKIE['studentscookie']['id'];
Это ненадежно. Злоумышленник может подставить себе любой id (куки ведь хранятся в браузере) и редактировать чужую страницу. Чтобы он этого не мог сделать, надо вместо предсказуемого id использовать сложный случайный код, который генерируется при регистрации (у каждого студента он свой и злоумышленник его не знает). 32 или больше символа из диапазона [a-z0-9] вполне подойдут.
> if($mapper->emailUsed($_POST['email']))
Имя функции начинается с глагола, например isEmailUsed. Также, не забывай всегда ставить {} после if.
> https://github.com/NotBadCode/Students/blob/master/index.php#L13
> https://github.com/NotBadCode/Students/blob/master/index.php#L27
У тебя тут 2 практически одинаковых ветки кода (редактирование и добавление). Попробуй объединить их в одну.
> https://github.com/NotBadCode/Students/blob/master/index.php#L37
> header("Location: index.php");
После header надо делать die так как нет смысла продолжать выполнения скрипта и что-то выводить: браузер это все равно не отобразит.
> https://github.com/NotBadCode/Students/blob/master/list.php#L5
> if(!isset($_COOKIE['studentscookie']['id'])){
То же самое, после header надо делать die. Ну и по условиям задачи список можно смотреть без регистрации. Ну и ты не должен молча пересылать пользователя на другую страницу. Ты должен в такой ситуации выводить там сообщение вроде «Список могут просматривать только зарегистрированные пользователи. Зарегистрируйтесь, чтобы полуить к нему доступ.»
Кстати, после обновления данных/регистрации надо выводить соответствующее сообщение. А то если форма молча перезагружается то не понятно — все в порядке или это ошибка какая-то?
> if(isset($_POST['submitsearch'])){
Для поиска (и других действий не меняющих данные на сервере) используют GET. Это позволяет например переслать ссылку на результаты поиска. Посмотри например как выглядит ссылка если зайти на http://ya.ru и что-нибудь поискать.
Аналогично, сортировка и постраничная навигация (она у тебя есть?) делается GET-ссылками.
> https://github.com/NotBadCode/Students/blob/master/lib/login.php
Это принято называть config.php или settings.php.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L9
> class DataMapper
В файле с классом не должно быть постороннего кода вроде «new PDO». Каждый класс должен быть назван с большой буквы, а имя файла соответсвовать имени класса: Class -> Class.php В одном файле может быть ровно один класс и ничего больше.
Насчет именования классов и файлов, есть стандарты:
http://www.php-fig.org/psr/psr-0/ru/
http://www.php-fig.org/psr/psr-4/ru/
То что я написал выше, примерно им соответствует (PSR-4 требует все классы класть в неймспейс, но в нашем приложении из 10 файлов это не имеет особого смысла).
Класс логично назвать не DataMapper, а ProfileMapper.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L11
> public $DBH;
Тут явно должно быть private или protected. Класс не должен не с кем делиться объектом PDO. И вообще, старайся как можно больше полей и методов делать закрытыми.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L21
> ORDER BY $sort $order");
Если ты подставляешь переменные в запрос, сделай тут же в функции проверку что они соответствуют разрешенному списку значений, иначе непонятно есть тут SQL инъекция или нет (SQL инъекция это когда злоумышленник вставляет свои данные в SQL запрос). Изучи теорию, проверь есть ли у тебя тут инъекция (я думаю есть) и добавь проверку:
https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0
http://forum.antichat.ru/thread43966.html
SQL инъекция при умелом использовании позволяет получить все данные из базы, а в тяжелых случаях еще и менять их, читать файлы на сервере, в том числе с паролями, то есть полностью взломать сайт.
> WHERE name LIKE :request
Там требуется искать по любой колонке.
> $STH->fetchAll(PDO::FETCH_CLASS,
Имей в виду что такая конструкция создает объект без вызова конструктора (это пример непраивльного проектирования: ситуаций когда объект создается в обход конструктора быть не должно. Тот кто это делал явно не разбирается в ООП). Это неприятно, так как можно долго искать почему код в конструкторе не срабатывает. Добавь хотя бы флаг PDO::FETCH_PROPS_LATE (мануал http://php.net/manual/ru/pdo.constants.php )
Вот пример кода: http://www.electrictoolbox.com/php-pdo-fetch-class-gotcha/
Вот вопрос на SO с хорошим примером исплоьзования FETCH_CLASS когда параметры передаются через конструктор: http://stackoverflow.com/a/9134544 но он годится только когда их немного (так как делать конструктор с 9 аргументами неправильно).
Анон, я проверил твой код. Вообще, не так плохо дял начинающего (ты наверно читал мои замечания к коду других анонов?). Но много чего надо исправить.
Советы и замечания по коду.
https://github.com/NotBadCode/Students
> `place` int(2) NOT NULL,
> `sex` int(1) NOT NULL,
Тут лучше подойдет ENUM. Я например смотрю на SQL код и не могу понять что значит 0 или 1. И другой человек, который захочет разобрать твой код, тоже не поймет без анализа кода.
В сложных случаях в SQL ты можешь добавлять комментарии к колонкам или всей таблице. Эти комментарии сохраняются в базе и отображаются в программах для работы с БД. Используй их: http://stackoverflow.com/a/200033
> `groupnum` int(5) NOT NULL,
Лучше номер группы сделать строкой. А то как ты будешь сохранять номер 00010?
> `year` int(4) NOT NULL,
Есть тип YEAR и догадайся-ка, для чего он придуман?
Я вижу ты плохо знаешь типы данных. Почитай (учить наизусть не надо, но ответ на вопрос «в чем хранить дату» или «в чем хранить номер телефона» или «в чем хранить сумму с копейками» знать надо):
http://phpclub.ru/mysql/doc/column-types.html
http://artemfedorov.ru/etc/mysql/field-types/
Также, если в таблице некоторые колонки не должны иметь повторы, добавь к ним уникальный ключ (UNIQUE KEY).
> https://github.com/NotBadCode/Students/blob/master/index.php#L3
После <?php не надо добавлять отступ (убрать оступ в большинстве редакторов можно выделив все и нажав Shift + Tab)
Также, я советую поставить в редакторе настройку «заменять таб на 4 пробела», а то смотри как у тебя код расползся на гитхабе некрасиво.
> $id=$_COOKIE['studentscookie']['id'];
Это ненадежно. Злоумышленник может подставить себе любой id (куки ведь хранятся в браузере) и редактировать чужую страницу. Чтобы он этого не мог сделать, надо вместо предсказуемого id использовать сложный случайный код, который генерируется при регистрации (у каждого студента он свой и злоумышленник его не знает). 32 или больше символа из диапазона [a-z0-9] вполне подойдут.
> if($mapper->emailUsed($_POST['email']))
Имя функции начинается с глагола, например isEmailUsed. Также, не забывай всегда ставить {} после if.
> https://github.com/NotBadCode/Students/blob/master/index.php#L13
> https://github.com/NotBadCode/Students/blob/master/index.php#L27
У тебя тут 2 практически одинаковых ветки кода (редактирование и добавление). Попробуй объединить их в одну.
> https://github.com/NotBadCode/Students/blob/master/index.php#L37
> header("Location: index.php");
После header надо делать die так как нет смысла продолжать выполнения скрипта и что-то выводить: браузер это все равно не отобразит.
> https://github.com/NotBadCode/Students/blob/master/list.php#L5
> if(!isset($_COOKIE['studentscookie']['id'])){
То же самое, после header надо делать die. Ну и по условиям задачи список можно смотреть без регистрации. Ну и ты не должен молча пересылать пользователя на другую страницу. Ты должен в такой ситуации выводить там сообщение вроде «Список могут просматривать только зарегистрированные пользователи. Зарегистрируйтесь, чтобы полуить к нему доступ.»
Кстати, после обновления данных/регистрации надо выводить соответствующее сообщение. А то если форма молча перезагружается то не понятно — все в порядке или это ошибка какая-то?
> if(isset($_POST['submitsearch'])){
Для поиска (и других действий не меняющих данные на сервере) используют GET. Это позволяет например переслать ссылку на результаты поиска. Посмотри например как выглядит ссылка если зайти на http://ya.ru и что-нибудь поискать.
Аналогично, сортировка и постраничная навигация (она у тебя есть?) делается GET-ссылками.
> https://github.com/NotBadCode/Students/blob/master/lib/login.php
Это принято называть config.php или settings.php.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L9
> class DataMapper
В файле с классом не должно быть постороннего кода вроде «new PDO». Каждый класс должен быть назван с большой буквы, а имя файла соответсвовать имени класса: Class -> Class.php В одном файле может быть ровно один класс и ничего больше.
Насчет именования классов и файлов, есть стандарты:
http://www.php-fig.org/psr/psr-0/ru/
http://www.php-fig.org/psr/psr-4/ru/
То что я написал выше, примерно им соответствует (PSR-4 требует все классы класть в неймспейс, но в нашем приложении из 10 файлов это не имеет особого смысла).
Класс логично назвать не DataMapper, а ProfileMapper.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L11
> public $DBH;
Тут явно должно быть private или protected. Класс не должен не с кем делиться объектом PDO. И вообще, старайся как можно больше полей и методов делать закрытыми.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L21
> ORDER BY $sort $order");
Если ты подставляешь переменные в запрос, сделай тут же в функции проверку что они соответствуют разрешенному списку значений, иначе непонятно есть тут SQL инъекция или нет (SQL инъекция это когда злоумышленник вставляет свои данные в SQL запрос). Изучи теорию, проверь есть ли у тебя тут инъекция (я думаю есть) и добавь проверку:
https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0
http://forum.antichat.ru/thread43966.html
SQL инъекция при умелом использовании позволяет получить все данные из базы, а в тяжелых случаях еще и менять их, читать файлы на сервере, в том числе с паролями, то есть полностью взломать сайт.
> WHERE name LIKE :request
Там требуется искать по любой колонке.
> $STH->fetchAll(PDO::FETCH_CLASS,
Имей в виду что такая конструкция создает объект без вызова конструктора (это пример непраивльного проектирования: ситуаций когда объект создается в обход конструктора быть не должно. Тот кто это делал явно не разбирается в ООП). Это неприятно, так как можно долго искать почему код в конструкторе не срабатывает. Добавь хотя бы флаг PDO::FETCH_PROPS_LATE (мануал http://php.net/manual/ru/pdo.constants.php )
Вот пример кода: http://www.electrictoolbox.com/php-pdo-fetch-class-gotcha/
Вот вопрос на SO с хорошим примером исплоьзования FETCH_CLASS когда параметры передаются через конструктор: http://stackoverflow.com/a/9134544 но он годится только когда их немного (так как делать конструктор с 9 аргументами неправильно).
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L35
> public function emailUsed($email)
Для проверки есть ли email не надо выбирать объект. Хватило бы SELECT COUNT(×) + fetchColumn().
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L49
> $STH->setFetchMode(PDO::FETCH_CLASS, 'profile');
Не используй setFetchMode, а передавай параметры прямо в fetch. Почему? Потому что setFetchMode делает код непредсказуемым: мы не знаем что нам вернет $STH->fetch так как не знаем с какими параметрами вызывалась setFetchMode до этого. В итоге мы теперь должны каждый раз ставить setFetchMode. Это в общем тоже пример неправильного проектирования, таких функций быть не должно.
> public function addStudent(Profile $profile)
Обычно такая функция после вставки должна получить id из базы и записать его в $profile.
> $STH->bindparam(":name", $name);
> $name=$profile->showName( );
Зачем ты испльзуешь bindParam? Он предназачен для двухсторонней привязки (с получением данных из базы) и почти никогда не нужен. Используй bindValue, в который данные можно передать без промежуточной переменной, и сделай функцию в 2 раза короче.
> public function getLastID()
Такой функции лучше не делать, так как результат который она вернет зависит от того какие функции вызывались ранее. Лучше при вставке в объект прописывать его id
> $STH=$this->DBH->query("SELECT COUNT(...
Это неправильно. Во-первых, в базе могут быть пропуски (записи удалялись) и надо писать MAX(id). Но и MAX(id) использовать неправильно из-за того что при параллельной регистрации получается такая ситуация:
- первый студент делает INSERT
- второй студент делает INSERT
- первый студент делает SELECT MAX(id) и полуает id второго студента
- второй студент делает то же самое
Видишь, какие сложные баги нам это принесет? К счастью, решение есть. У PDO есть метод lastInsertId который возвращает id последней вставленной записи в текущем сеансе связи с базой.
https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L122
> $id=$result;
> return $id;
Что за ерунда? Может еще десяток переменных добавим?
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L20
> if($id!="") $this->id=$data['id'];
Пиши в 3 строчки и через {}
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L15
> public function setFields($data)
У тебя в одной функции объединено 2 вещи: простановка полей из массива и проверка на правильность. Надо разнести их в 2 отдельных функции, а то проверку нельзя вызвать без установки значений. Неудобно и нелогично.
Ну и еще, ты при ошибке не меняешь свойства объекта. Но ведь это значит что при вводе неправильного значения пользователь увидит пустую форму и все введенные данные потеряются. Лучше сначала скопировать все значения в объект, а потом проверять сам объект.
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L36
> $regExp="/^[a-zA-Z0-9_+.-]+@[a-z0-9.-]+(\.)[a-z]{2,}$/ui";
Почитай статью:
http://habrahabr.ru/post/55820/
http://habrahabr.ru/post/175375/
Я от себя посоветовал бы во второй регулярке поменять точку на \S. Это защитит от ошибок когда пользователи вместо @ пишут пробел. Хотя твоя регулярка неплохая и годится для задачи.
Ну и знай что в PHP есть функция для валидации email (хотя мне эта функция не нравится, так как она встроена в PHP и ты не можешь никак на нее повлиять):
http://php.net/manual/ru/filter.filters.validate.php
http://php.net/manual/ru/book.filter.php
> if($id!="") $this->id=$data['id'];
А зачем ты id ставишь из входящих данных? Чтобы можно было редактировать чужой профиль что ли?
> $regExp="/^[а-яa-zё-]+$/ui";
> $regExp="/^[0-9]+$/";
Тут надо разные переменные. Почитай: http://learn.javascript.ru/write-unmain-code#повторно-используйте-имена
> $data['year']<1990
Люди старше 25 не нужны?
> public function showID()
Это принято называть getId().
Сортировку я думаю лучше сделать не формой, а в виде кликабельных заголовков у таблицы со стрелочками. Так надо меньше кликов чтобы отсортировать таблицу. Вот как тут: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%B3%D0%BE%D1%80%D0%BE%D0%B4%D0%BE%D0%B2_%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8 только с перезагрузкой страницы.
> https://github.com/NotBadCode/Students/blob/master/templates/list.html#L33
Надо исплоьзовать <?php так как <? может быть отключено.
> https://github.com/NotBadCode/Students/blob/master/templates/list.html#L41
для вывода таблиц есть теги table, tr, th, td:
http://htmlbook.ru/samhtml/tablitsy
http://htmlbook.ru/html/table
Также, я вижу что ты исплоьзуешь br, то есть плохо знаешь верстку. Не хочешь как-нибудь порешать мои задачки на HTML/CSS?
> https://github.com/NotBadCode/Students/blob/master/templates/profile.html#L13
> <input type="text" name="name"
Имя надо выводить не рядом с полем, а в поле. Для этого там есть атрибут value:
http://htmlbook.ru/html/input/value
Для выпадающих списков и радиокнопок тоже можно задать значение по умолчнаию:
http://htmlbook.ru/html/input/checked
http://htmlbook.ru/html/option/selected
> <?if($error=="sex"):?> style="border:2px solid red;"
лучше не писать стили, а добавить CSS класс. Тогда мы легко можем менять вид проблемного инпута через CSS. Явно стоит тебе порешать мои задачки на верстку.
> https://github.com/NotBadCode/Students/blob/master/templates/profile.html#L50
> <? if($showlist==1){?>
Тут надо версию if с двоеточием. Ибо вот это <?php } ?> плохо заметно в HTML-коде, endif заметнее.
И еще. У тебя 2 шаблона и в обоих скопипащена шапка и подвал. Избавься от копипасты.
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L35
> public function emailUsed($email)
Для проверки есть ли email не надо выбирать объект. Хватило бы SELECT COUNT(×) + fetchColumn().
> https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L49
> $STH->setFetchMode(PDO::FETCH_CLASS, 'profile');
Не используй setFetchMode, а передавай параметры прямо в fetch. Почему? Потому что setFetchMode делает код непредсказуемым: мы не знаем что нам вернет $STH->fetch так как не знаем с какими параметрами вызывалась setFetchMode до этого. В итоге мы теперь должны каждый раз ставить setFetchMode. Это в общем тоже пример неправильного проектирования, таких функций быть не должно.
> public function addStudent(Profile $profile)
Обычно такая функция после вставки должна получить id из базы и записать его в $profile.
> $STH->bindparam(":name", $name);
> $name=$profile->showName( );
Зачем ты испльзуешь bindParam? Он предназачен для двухсторонней привязки (с получением данных из базы) и почти никогда не нужен. Используй bindValue, в который данные можно передать без промежуточной переменной, и сделай функцию в 2 раза короче.
> public function getLastID()
Такой функции лучше не делать, так как результат который она вернет зависит от того какие функции вызывались ранее. Лучше при вставке в объект прописывать его id
> $STH=$this->DBH->query("SELECT COUNT(...
Это неправильно. Во-первых, в базе могут быть пропуски (записи удалялись) и надо писать MAX(id). Но и MAX(id) использовать неправильно из-за того что при параллельной регистрации получается такая ситуация:
- первый студент делает INSERT
- второй студент делает INSERT
- первый студент делает SELECT MAX(id) и полуает id второго студента
- второй студент делает то же самое
Видишь, какие сложные баги нам это принесет? К счастью, решение есть. У PDO есть метод lastInsertId который возвращает id последней вставленной записи в текущем сеансе связи с базой.
https://github.com/NotBadCode/Students/blob/master/lib/pdo.php#L122
> $id=$result;
> return $id;
Что за ерунда? Может еще десяток переменных добавим?
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L20
> if($id!="") $this->id=$data['id'];
Пиши в 3 строчки и через {}
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L15
> public function setFields($data)
У тебя в одной функции объединено 2 вещи: простановка полей из массива и проверка на правильность. Надо разнести их в 2 отдельных функции, а то проверку нельзя вызвать без установки значений. Неудобно и нелогично.
Ну и еще, ты при ошибке не меняешь свойства объекта. Но ведь это значит что при вводе неправильного значения пользователь увидит пустую форму и все введенные данные потеряются. Лучше сначала скопировать все значения в объект, а потом проверять сам объект.
> https://github.com/NotBadCode/Students/blob/master/lib/profile.php#L36
> $regExp="/^[a-zA-Z0-9_+.-]+@[a-z0-9.-]+(\.)[a-z]{2,}$/ui";
Почитай статью:
http://habrahabr.ru/post/55820/
http://habrahabr.ru/post/175375/
Я от себя посоветовал бы во второй регулярке поменять точку на \S. Это защитит от ошибок когда пользователи вместо @ пишут пробел. Хотя твоя регулярка неплохая и годится для задачи.
Ну и знай что в PHP есть функция для валидации email (хотя мне эта функция не нравится, так как она встроена в PHP и ты не можешь никак на нее повлиять):
http://php.net/manual/ru/filter.filters.validate.php
http://php.net/manual/ru/book.filter.php
> if($id!="") $this->id=$data['id'];
А зачем ты id ставишь из входящих данных? Чтобы можно было редактировать чужой профиль что ли?
> $regExp="/^[а-яa-zё-]+$/ui";
> $regExp="/^[0-9]+$/";
Тут надо разные переменные. Почитай: http://learn.javascript.ru/write-unmain-code#повторно-используйте-имена
> $data['year']<1990
Люди старше 25 не нужны?
> public function showID()
Это принято называть getId().
Сортировку я думаю лучше сделать не формой, а в виде кликабельных заголовков у таблицы со стрелочками. Так надо меньше кликов чтобы отсортировать таблицу. Вот как тут: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%B3%D0%BE%D1%80%D0%BE%D0%B4%D0%BE%D0%B2_%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8 только с перезагрузкой страницы.
> https://github.com/NotBadCode/Students/blob/master/templates/list.html#L33
Надо исплоьзовать <?php так как <? может быть отключено.
> https://github.com/NotBadCode/Students/blob/master/templates/list.html#L41
для вывода таблиц есть теги table, tr, th, td:
http://htmlbook.ru/samhtml/tablitsy
http://htmlbook.ru/html/table
Также, я вижу что ты исплоьзуешь br, то есть плохо знаешь верстку. Не хочешь как-нибудь порешать мои задачки на HTML/CSS?
> https://github.com/NotBadCode/Students/blob/master/templates/profile.html#L13
> <input type="text" name="name"
Имя надо выводить не рядом с полем, а в поле. Для этого там есть атрибут value:
http://htmlbook.ru/html/input/value
Для выпадающих списков и радиокнопок тоже можно задать значение по умолчнаию:
http://htmlbook.ru/html/input/checked
http://htmlbook.ru/html/option/selected
> <?if($error=="sex"):?> style="border:2px solid red;"
лучше не писать стили, а добавить CSS класс. Тогда мы легко можем менять вид проблемного инпута через CSS. Явно стоит тебе порешать мои задачки на верстку.
> https://github.com/NotBadCode/Students/blob/master/templates/profile.html#L50
> <? if($showlist==1){?>
Тут надо версию if с двоеточием. Ибо вот это <?php } ?> плохо заметно в HTML-коде, endif заметнее.
И еще. У тебя 2 шаблона и в обоих скопипащена шапка и подвал. Избавься от копипасты.
А, еще. В PHP выражениях принято ставить пробелы вокруг знаков:
$id = $x->method($a) + $b;
Но как видишь, не все знаки отделяются пробелами. Старайся ставить их или пропусти код через phpformatter.com — он вроде их ставит.
Спасибо анон, ты тут расписал больше чем дал мне вузик за полгода.
Буду исправлять.
Почему ты так критично относишься к ифам без фигурных скобок?
А с вёрсткой просто было лень заморачиваться
так то у меня есть несколько сверстаных макетов на гитхаб.
заводить новые переменные со странными именами (что за sta?) не надо. можно написать
start = start || 0;
без var так как эта переменная и так уже создана.
А так, верно.
>>440033
Это приводит к ошибкам. Так как если ты видишь
if (...)
action;
и дописываешь еще одну команду то она не попадет в if. Проще всегда ставить скобки чем усложнять себе жизнь разбором что относится к нему, а что нет.
В особо запущенных случаях бывает 2 ифа или else или цикл с ифом и разобраться уже сложнее.
Вдобавок, рекомендация по оформлению кода PSR-2 ( http://www.php-fig.org/psr/psr-2/ru/ ) говорит:
> Тело каждой управляющей структуры НЕОБХОДИМО заключать в фигурные скобки. Это стандартизирует вид управляющих структур и уменьшает вероятность возникновения ошибок при добавлении новых строк в тело.
А если ты не ставишь скобки то скобки за тобой придется ставить кому-то другому при редактировании.
заводить новые переменные со странными именами (что за sta?) не надо. можно написать
start = start || 0;
без var так как эта переменная и так уже создана.
А так, верно.
>>440033
Это приводит к ошибкам. Так как если ты видишь
if (...)
action;
и дописываешь еще одну команду то она не попадет в if. Проще всегда ставить скобки чем усложнять себе жизнь разбором что относится к нему, а что нет.
В особо запущенных случаях бывает 2 ифа или else или цикл с ифом и разобраться уже сложнее.
Вдобавок, рекомендация по оформлению кода PSR-2 ( http://www.php-fig.org/psr/psr-2/ru/ ) говорит:
> Тело каждой управляющей структуры НЕОБХОДИМО заключать в фигурные скобки. Это стандартизирует вид управляющих структур и уменьшает вероятность возникновения ошибок при добавлении новых строк в тело.
А если ты не ставишь скобки то скобки за тобой придется ставить кому-то другому при редактировании.
>заводить новые переменные со странными именами (что за sta?) не надо. можно написать
>start = start || 0;
Спасибо.
А какая кодировка будет использоваться по умолчанию во всяких простых немультибайтовых строковых функциях? Та что в дефолтной локали?
Да. Причем так как эти функции воспринимают любой текст как 8-битный то utf8 коды символов будут искажены и получится битый текст. У меня чуть чуть этот тут описано: https://gist.github.com/codedokode/ff99e357e9860ea169b8
То есть функции типа strtoupper можно исплоьзовать только с 8-битными кодировками с правильнйо локалью. Не рекомендую их вообще использовать.
https://github.com/tokotun/uppy
Что то у меня не пошла автозагрузка средствами композитора.
классам написал namespase App;
и в composer.json
{
"autoload": {"psr-4": {"App\\": "uppy/"}}
}
Но не заработало. Пришлось сделать так как сделал.
Может надо писать "App" : "uppy/App" ?
> 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.
В твоем случае он при автозагрузке App\\Class будет искать uppy/Class.php а не uppy/App/Class.php
Не забудь после изменений вызвать команду для перегенерации автозагрузчика:
> After adding the autoload field, you have to re-run dump-autoload to re-generate the vendor/autoload.php file.
Алсо, сейчас у тебя классы не в namespace App. Этот например https://github.com/tokotun/uppy/blob/master/uppy/App/FileMapper.php в глобальном неймспейсе.
Ну и называть неймспейс App плохая идея, лучше название проекта использовать. Ведь идея неймспейсов в защите от конфликтов имен, а если все будут называть неймспейс App то конфликты будут.
http://pastebin.com/xxzhi0ab
>use или указать namespace в index.php не забыл?
А то как же. Конечно забыл.
Но тут появилась новая проблемка.
Argument 1 passed to Uppy\FileMapper::__construct() must be an instance of Uppy\PDO, instance of PDO given, called in C:\server\localhost\www\uppy\index.php on line 28 and defined
https://github.com/tokotun/uppy/blob/master/index.php#L28
и
https://github.com/tokotun/uppy/blob/master/uppy/app/FileMapper.php#L7
Насколько я понял, тут PDO при импорте получило неймспейс Uppy.
Как исправить?
О, спасибо. Заработало.
Есть 2 косяка: http://jsfiddle.net/8xypLhot/1/
- текст статьи вываливается влево под меню
- пункт меню с длинным текстом переносится на вторую строку, и она выглядит как отдельный пункт. Надо чтобы при перенносе межстрочное расстояние не было таким большим.
> <div id="header">
>\t<h1>
Тут в принипе div не нужен
Ну и насчет полей. Такие вещи обычно проще делать через паддинг на родителе (body например) чем на каждом элементе ставить margin 10px;
> font-family: 'Trebuchet MS';
Надо объявлять тут еще станадртный шрифт вроде serif/sans-serif на случай если требушета нет.
> \tvertical-align: top;
Это свойство применяется только для 2 вещей:
- выравнивание контента в ячейке таблицы
- выравнивание inline/inline-block друг относительно друга в строке
Тут оно ни на что не влияет, значит ты поставил его наугад. Почитай про него например тут: http://css-live.ru/articles/ikf-vertikalnoe-vyravnivanie-v-stroke-chast-1-8-ya-publikaciya-cikla-tajny-css2-1%E2%80%B3.html
Пруф что vertical align не влияет тут ни на что: http://jsfiddle.net/8xypLhot/2/
Видишь, текст все равно по центру вертикально выровнен.
Также, не применяй стили к ul. Ведь в тексте на главной тоже может встретиться список и ты своими стилями его сломаешь. Сделай класс и применяй стили к нему.
> И зачем тут использовать свойство clear? Я в этой задаче не нашел ему применения.
Не знаю, если он не нужен то не надо конечно. Может там имелось в виду что надо просто выучить это свойство?
>>440369
В апаче есть mod_rewrite который позволяет определить какой скрипт должен вызываться, но используя нестандартную конфигурацию ты рискуешь что что-то не заработает.
mod_rewrite это не редирект. Он задает правила например что при обращении по адресу /x/ надо вызывать скрипт y.php причем там можно использовать регулярные выражения.
habr http://habrahabr.ru/company/sprinthost/blog/129560/
docs http://httpd.apache.org/docs/2.4/rewrite/
Все равно баг есть, достаточно добавить текста или сузить окно http://jsfiddle.net/8xypLhot/4/
Ну и ставить высоту в 900px это значит что на низних экранах появляется бесполезная линейка прокрутки.
3/7
http://ideone.com/u1v1Lb
Но есть вопрос, внутри функции fixText я хотел запихнуть регулярные выражения как $key и то, на что надо заменять результат поиска как $value в массив и пройти foreach, но чего-то не то оно делает, первый проход норм, а второй исправляет уже исправленное, причем непонятно по какой логике это делает, а вот так по отдельности все ок. Чому так?
function oneFile($id) {
global $con;
$q=mysql_query("SELECT*FROM files WHERE id='$id'");
while($row=mysql_fetch_assoc($q)) {
$row1[]=$row;
}
return $row1;
}
Скажите, он очень костыльный?
Очень.
>global $con;
Перед тем как использовать глобальные переменные, сто раз подумай, можно ли обойтись без них.
>mysql_query
Почитай http://getjump.github.io/ru-php-the-right-way/#Базы_данных
Возникла задача спроектировать с нуля достаточно объемное и как можно более удобное веб-приложение энтерпрайзного толка. Я понял, что, если с ui паттернами для десктопного приложения такого плана я знаком, то вот с тем, как это делают в вебе, я не знаком совсем.
Есть ли какие-то хорошие гайды, книги или примеры, которые можно будет взять за основу?
>error_reporting ( - 1 );
Молодец, серьезно. И не убирай это в продакшене, как советуют всякие.
В строке 15 ты, по факту, уже нашел первые буквы всех предложений во второй подмаске, ([a-z|а-я]). Кстати, символ | тебе тут не нужен, символьные классы в регулярках группируются без него.
Давай не будем делать двойную работу (строки 16-24).
Строки с 15 по 24 можно заменить так - http://ideone.com/tp1KOA
Ты давай либо код, либо задачу.
Описывать неработающий код словами, да еще без уточнения, что конкретно ты делаешь (например, заменяешь кавычки, угадал?) - самая плохая постановка вопроса.
Никто тебе так не поможет.
> И не убирай это в продакшене, как советуют всякие.
Вообще-то error_reporting отвечает за игнорирование некоторых видов ошибок (странная настройка: кто может захотеть игнорировать ошибки?). За вывод на экран отвечает другая настройка, display_errors.
Дело в другом.
Некоторые гуру считают нормальным, что их код бросается нотисами, и учат других писать то же самое.
Вот в скрипте у меня есть условие, при прохождении которого начинается работа с переменными сесии. Собственно у меня вопрос, session_start лучше писать непосредственно перед работой с этими переменными? Или лучше писать в начале скрипта? А если в начале скрипта, то нормально ли написать эту строчку в отдельном файле с другими штуками, который инклудится в начале каждого файла?
В общем уточню.
Речь о том, что бы всю подобную копипасту разбросанную по файлам, написать в одном файле и инклудить его в начале каждого файла со скриптом.
http://ideone.com/P6OkF4
Сначала у меня был только файл config.php, в котором был массив для коннекта к базе и ничего больше, и я инклудил его непосредственно перед работой с базой. Но потом 1 товарищ указал мне на то, что у меня error_reporting в начале каждого файла написано, а так же session_start разбросаны по скрипту, и посоветовал всё такое скинуть в отдельный файл и его инклудить.
Единственное что меня смущает, так это то, что когда я читал инфу про сессии, там вроде бы не рекомендовалось писать session_start в начале скрипта, а делать это только когда начинается работа с сессией непосредственно. В общем жду пояснений от гуру.
>Это ненадежно. Злоумышленник может подставить себе любой id (куки ведь хранятся в браузере) и редактировать чужую страницу. Чтобы он этого не мог сделать, надо вместо предсказуемого id использовать сложный случайный код, который генерируется при регистрации (у каждого студента он свой и злоумышленник его не знает). 32 или больше символа из диапазона [a-z0-9] вполне подойдут.
Мне нужно так же хранить этот код в базе и возвращать нужного студента проверяя этот код?
О, ура, спасибо что посмотрел!
Такс:
>Не вижу где в репозитории конфигурация для mongoDB. Например, где определяются индексы? Где создаются коллекции?
Эм, индексы я вообще не создавал, отложил это на попозже, и так и не сделал. А коллецкии разве надо руками создавать? Мне показалось они сами создаются, если их не существует, но ты в неё пишешь.
Кстати где в коде это делать? Что, каждый раз при запуске PHP скрипта, проверять, есть ли нужные коллекции\индексы? Это же разовая процедура должна быть
>озможно, ты копировал схему котору. использует Silex
Ага, хотел чтоб было также как в веб-части.
>Гораздо лучше если бы и websocket сервер и приложение разделяли общий контейнер
Тогда в серверной части в контейнере лежало бы куча всякого, ему вообще ненужного
>Обычно в мапперах реализуют подход IdentityMap
>Зачем вообще нужны Handler-классы?
Вот handler классы я изначально как раз и делал, для того, чтоб они кешировали обьекты RoomUser и RoomEvent, чтоб не было повторных обращений к БД, когда мы теже самые обьекты пытаемся получить. Но, по ходу дела понял, что это очень плохая идея, т.к. у нас есть два "писателя" в БД, server и webapp, Соответственно, Webapp что то поменял в коллекции RoomUser - как RoomUserHandler в Server части об этом узнает? В общем фигня вышла, я этот код выкинул, а ненужные промежуточные классы остались.
>Насчет проблемы с заходом пользователя с нескольких устройств или вкладок, тебе надо вместо пользователя ввести понятие «соединения»
Да, я пришел точно к такому же выводу: https://github.com/d-beekeeper/ratchat/issues/1
Только жаль что поздно до этого додумался. Надо приличный кусок кода под это дело теперь переделывать.
Сначала думал, что можно будет обойтись "малой кровью" - простым счетчиком заходов юзера в отдельную комнату. Типа юзер зашел - увеличиваем. Вышел - уменьшаем. Эвент выхода генерим только когда счетчик==0. Но Heartbeater с таким решением не совместим в принципе. А соединения так просто не добавить, ибо там у каждого должен быть уникальный ID и т.д.
Кроме того, в серверно части эти самые соединения есть - на уровне Ratchet. И как раз именно с уникальными ID. А значит webapp-соединение должно быть совместимо в server-соединением - в общем тут надо подумать, как грамотно сделать. Возможно вообще реализовать аналог WAMP, но с транспортом в виде периодических ajax запросов вместо WebSockets.
> protected function convertId($_id)
>Это очень странная функция
>Это какой-то кривой костыль, явно.
Йап, ты как всегда прав. Надо переделать. А:
> if (!\MongoId::isValid($_id)) {
> $_id = substr(md5($_id),0,24);
это из за того, что если мы сделаем new MongoId('some_custom_string') - будет ошибка. Почему то в PHP Mongo-клиенте, если мы создаем MongoId - ему обязательно нужно передавать hex строку (типа fa3fcc2e...) длиной ровно 24 символа. При том, что сам mongo server прекрасно хавает любые произвольные строки в качестве _id. ХЗ почему так.
>Не очень понятно, почему ты прововеряешь равенство поля null через isset, и не очень понятно почему такие поля не попадают в массив.
Ну... я подумал что не имеет смысла сохранять в БД поля, которые null... зачем они там? Только для однообразности?
О, ура, спасибо что посмотрел!
Такс:
>Не вижу где в репозитории конфигурация для mongoDB. Например, где определяются индексы? Где создаются коллекции?
Эм, индексы я вообще не создавал, отложил это на попозже, и так и не сделал. А коллецкии разве надо руками создавать? Мне показалось они сами создаются, если их не существует, но ты в неё пишешь.
Кстати где в коде это делать? Что, каждый раз при запуске PHP скрипта, проверять, есть ли нужные коллекции\индексы? Это же разовая процедура должна быть
>озможно, ты копировал схему котору. использует Silex
Ага, хотел чтоб было также как в веб-части.
>Гораздо лучше если бы и websocket сервер и приложение разделяли общий контейнер
Тогда в серверной части в контейнере лежало бы куча всякого, ему вообще ненужного
>Обычно в мапперах реализуют подход IdentityMap
>Зачем вообще нужны Handler-классы?
Вот handler классы я изначально как раз и делал, для того, чтоб они кешировали обьекты RoomUser и RoomEvent, чтоб не было повторных обращений к БД, когда мы теже самые обьекты пытаемся получить. Но, по ходу дела понял, что это очень плохая идея, т.к. у нас есть два "писателя" в БД, server и webapp, Соответственно, Webapp что то поменял в коллекции RoomUser - как RoomUserHandler в Server части об этом узнает? В общем фигня вышла, я этот код выкинул, а ненужные промежуточные классы остались.
>Насчет проблемы с заходом пользователя с нескольких устройств или вкладок, тебе надо вместо пользователя ввести понятие «соединения»
Да, я пришел точно к такому же выводу: https://github.com/d-beekeeper/ratchat/issues/1
Только жаль что поздно до этого додумался. Надо приличный кусок кода под это дело теперь переделывать.
Сначала думал, что можно будет обойтись "малой кровью" - простым счетчиком заходов юзера в отдельную комнату. Типа юзер зашел - увеличиваем. Вышел - уменьшаем. Эвент выхода генерим только когда счетчик==0. Но Heartbeater с таким решением не совместим в принципе. А соединения так просто не добавить, ибо там у каждого должен быть уникальный ID и т.д.
Кроме того, в серверно части эти самые соединения есть - на уровне Ratchet. И как раз именно с уникальными ID. А значит webapp-соединение должно быть совместимо в server-соединением - в общем тут надо подумать, как грамотно сделать. Возможно вообще реализовать аналог WAMP, но с транспортом в виде периодических ajax запросов вместо WebSockets.
> protected function convertId($_id)
>Это очень странная функция
>Это какой-то кривой костыль, явно.
Йап, ты как всегда прав. Надо переделать. А:
> if (!\MongoId::isValid($_id)) {
> $_id = substr(md5($_id),0,24);
это из за того, что если мы сделаем new MongoId('some_custom_string') - будет ошибка. Почему то в PHP Mongo-клиенте, если мы создаем MongoId - ему обязательно нужно передавать hex строку (типа fa3fcc2e...) длиной ровно 24 символа. При том, что сам mongo server прекрасно хавает любые произвольные строки в качестве _id. ХЗ почему так.
>Не очень понятно, почему ты прововеряешь равенство поля null через isset, и не очень понятно почему такие поля не попадают в массив.
Ну... я подумал что не имеет смысла сохранять в БД поля, которые null... зачем они там? Только для однообразности?
Баланс отрицательный быть не должен. Смотри что получается, когда вместо 40 тысяч вписать кредит 5100
http://ideone.com/alQWUN
Сумма меняется в разные стороны, сначала было 10к, а стало 7.
Нужно проверять не отрицательную сумму, а меньше ли оставшийся долг наших ежемесячных выплат, чтобы не переплачивать и не загонять баланс ниже нуля.
>Что за странный <a> без href?
>Это ты скопировал или у тебя правда адаптивный дизайн?
Эм, ну это все копипаста из заготовленных шаблонов на на странице мануала по Bootstrap
>Мне кажется, если вебсокет отвалился, но соединение возможно, лучше повторно соединяться через WS.
Это все вшито в AutobahnJs client - он там сам пытается реконнектить вебсокет. см. ниже:
{
skipSubprotocolCheck:true,
maxRetries: 5,
retryDelay: 1000
}
5 попыток реконнета через 1000 мс. И только если не удалось - тогда вызвается onDisconnectCallback
>У тебя на клиенте есть какое-то ограничение на число отображаемых сообщений?
Неа, учту.
> alert('Ошибка: ' + value);
Да я это прекрасно понимаю, просто лень уже был писать модально-всплывающую фигню для отображения ошибок. Потом когда нить доделаю.
> if ($(this).queue().length == 0)
>Это вообще где-то в документации описано?
Нуу... там написано что очередь можно повесить на любой обьект. Ну я и повесил... надо же было её куда то приткнуть, мне показалось что так - норм вариант.
>Кстати, как у тебя с очисткой старых сообщений? Они когда-нибудь очищаются?
Неа. По хорошему надо отдельную коллекцию - архив эвентов сделать, и туда переносить из основной коллекции events старые.
>Ну и вторая вещь, которой можно было бы заняться, это покрыть приложение тестами.
Да, я это читал и писал с рассчетом на то, чтоб потом тесты можно было прикрутить относительно легко.
Займусь всем этим чуть позже. Щас пока не до чата. Во первых заколебался я его делать - это было совсем не просто без соотв. опыта, а во вторых щас немного не до этого: работаю джуном и ищу работу на позицию мидла, так что можешь скрестить за меня пальцы - твои уроки не проходят даром.
>Что за странный <a> без href?
>Это ты скопировал или у тебя правда адаптивный дизайн?
Эм, ну это все копипаста из заготовленных шаблонов на на странице мануала по Bootstrap
>Мне кажется, если вебсокет отвалился, но соединение возможно, лучше повторно соединяться через WS.
Это все вшито в AutobahnJs client - он там сам пытается реконнектить вебсокет. см. ниже:
{
skipSubprotocolCheck:true,
maxRetries: 5,
retryDelay: 1000
}
5 попыток реконнета через 1000 мс. И только если не удалось - тогда вызвается onDisconnectCallback
>У тебя на клиенте есть какое-то ограничение на число отображаемых сообщений?
Неа, учту.
> alert('Ошибка: ' + value);
Да я это прекрасно понимаю, просто лень уже был писать модально-всплывающую фигню для отображения ошибок. Потом когда нить доделаю.
> if ($(this).queue().length == 0)
>Это вообще где-то в документации описано?
Нуу... там написано что очередь можно повесить на любой обьект. Ну я и повесил... надо же было её куда то приткнуть, мне показалось что так - норм вариант.
>Кстати, как у тебя с очисткой старых сообщений? Они когда-нибудь очищаются?
Неа. По хорошему надо отдельную коллекцию - архив эвентов сделать, и туда переносить из основной коллекции events старые.
>Ну и вторая вещь, которой можно было бы заняться, это покрыть приложение тестами.
Да, я это читал и писал с рассчетом на то, чтоб потом тесты можно было прикрутить относительно легко.
Займусь всем этим чуть позже. Щас пока не до чата. Во первых заколебался я его делать - это было совсем не просто без соотв. опыта, а во вторых щас немного не до этого: работаю джуном и ищу работу на позицию мидла, так что можешь скрестить за меня пальцы - твои уроки не проходят даром.
> проверять не отрицательную сумму, а меньше ли оставшийся долг наших ежемесячных выплат
Сделать проверку на 5 тысяч? Но получается еще большая хрень. В последний месяц остается 4100 долга, можно было бы выплатить одним разом, но банк начисляет комиссию в 1000 до твоей выплаты. В итоге получается долга 5100 и за последний месяц его выплатить не удается. Криво объясняю, но все же. Вот как получается, если сделать по твоему совету.
http://ideone.com/Dq300w
>month++
>$paymentTotal = $paymentTotal + $creditBalance;
Костыль какой-то, лучше сделать, чтобы выплачивалось все в следующем цикле, а не в текущем. А так у тебя к текущей выплате прибавляется оставшийся баланс без процентов и без сервис пеймента. Там должна быть сумма больше чем 59 тысяч. В итоге у тебя должна получится 61 тысяча с чем-то. Но с формулой
$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
у тебя такой ответ не получится хотя тут я немного приврал, можно получить, но тебе я советую её переделать потому-что она сразу отнимает месячную выплату от баланса, не проверив при этом оставшуюся сумму кредита. Наверное сумбурно объяснил, ОП придет и расскажет подробнее.
> чтобы выплачивалось все в следующем цикле, а не в текущем
Я имел ввиду итерацию цикла, а не цикл, конечно же.
ну так подразумевается, что банк начисляет тебе в начале месяца, а платишь ты например только в конце. Ты можешь сделать и наоборот, если хочешь. Ты тут просто моделируешь реальную жизнь, ты можешь даже рандомить себе карманные деньги, которые ты сможешь выплачивать, или дату их поступления. Типа выплачивать до или после начисления.
Сначала определи сам как все происходит ирл, а потом напрограммируй это.
>Строки с 15 по 24 можно заменить так
Спасибо, учту.
>Ты давай либо код, либо задачу.
http://ideone.com/ldeKxk Вот такую конструкцию я имел в виду. Неуверен в ее необходимости в данной задаче, но захотелось почему-то применить foreach.
http://jsfiddle.net/3y7uugvk/ 7 зачада. Кстати, в жсфиддле пришлось высоту другую указывать, в хроме у меня почему-то когда 30 пикселей указываешь, то высота блока такой и будет.
>440754
>костыль
Именно! Я программирую первый день, и уже занимаюсь придумыванием каких-то костылей. Как поизящнее решить эту задачу? Допиши её как будет правильнее, уже весь мозг себе сломал, ничего кроме костылей в голову не идёт.
>Допиши её как будет правильнее
Я, конечно, мог бы, но этим самым скорее окажу тебе медвежью услугу.
Пытаюсь сделать вывод уменьшенной копии изображения. Но вместо изображения эта функция выводит кракозябры.
https://github.com/tokotun/uppy/blob/master/uppy/app/functions.php#L25
Думал что возможно не подключены какие либо библиотеки в PHP. Но этот код работал, когда запускал его в отдельном файле test.php.
Я уже решил задачу, хоть и криво. Теперь мне нужно видеть, как оно должно быть в идеале. Чтобы было к чему стремиться.
Я бы не сказал, что ты её решил, ведь результат у тебя не тот, что должен быть, сумма другая выходит и месяцы тоже. Но это нормально, эту задачу почти никто за 1 день не решает. ОП придет и поможет тебе разобраться.
Я не слово не говорил тебе про костыли, но
вот этот:
if ($creditBalance < 5000) {
$paymentTotal = $paymentTotal + $creditBalance;
$creditBalance = 0;
$month ++;
echo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
echo "С меня хватит!\n";
break;
}
действительно выглядит странным. Попробуй переписать его, что бы все шло своим чередом. Но когда у тебя долг становится меньше чем твой ежемесячный платеж, то и выплата в этом месяце идет равная этому долгу.
Еще вот тут:
for ($month = 1; $month <= 20; $month ++) {
можешь задать условие, что у тебя будет цикл идти не пока пройдет 20 месяцев, а пока не кончится долг, это тоже избавит тебя от костылей.
Ключевой момент, что ты сразу отнимаешь месячную выплату вот здесь
$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
А потом у тебя уже идет проверка на условие. То есть допустим у тебя долг 4 тысячи. От них нам нужно посчитать проценты и добавить к сумме + сервис пеймент. Но мы тут же отнимаем от этой суммы 5 тысяч и долг уходит в минус. По логике мы сначала вычисляем сумму кредита, потом проверяем не меньше ли она ежемесячной выплаты, а уж затем отнимаем от кредита какую-то сумму в зависимости от проверки.
Предзащита значится у меня в мае и вот такой вопрос. Реально если ты полной ноль в php и mysql сделать то, что описано выше?
>Реально если ты полной ноль в php и mysql сделать то, что описано выше?
Стоп, а чем ты занимался все эти 5 курсов?
http://ideone.com/3eLJRc
вот держи, комментариями попробовал объяснить как смог.
Вот >>440829 он тебе тоже всё верно сказал, что у тебя математическая модель не отражает реальности. Не нужно пытаться все пихать в одну кучу с вычислениями. Может между этими вычислениями нужна проверка, которая повлияет на второе действие. Поэтому лучше разбивать всё на действия в таком случае, и каждое действие писать в отдельной строчке. Что бы логика и смысл был во всем.
Ну по секрету скажу что php было пол года и у половины группы, в которую я не входил и было это 2 года назад. А после 2 года мы познавали маркетинг, менеджмент и как надо правильно расставлять товары на полки магазинов.
Ну ты паскаль то знаешь хотя бы, информатик? Цикл запустить умеешь? Я вот дрочу уже год пхп и по твоему описанию чет не могу понять как бы я делал эту программу учета.
Какая-то нифига не прикладная у вас информатика, если программированию из 5 лет учат всего пол-года, да и еще и у одной половины группы. Что же учила вторая? Какой-то язык ты должен ведь знать?
Да типичная история. У меня такая же хрень была в вузе, но я еще и заочник был. По факту вся группа попиздила в интернете курсовых и даже защитить не могла, не зная где тут цикл, а где условия. Я со школьными знаиями по паскалю на фоне этого цирка выглядил как античный бог на сверкающем пегасе среди чумного города.
Коли так, то какие книги лучше всего для этого читать? Желательно на русском.
php
http://archive-ipq-co.narod.ru/
html
https://gist.github.com/codedokode/58ebc90bd006baf4b35c
MySQL
https://gist.github.com/codedokode/10539213
Вот как то так, тут основы основ. Ведь что бы сваять твоё задание на тяп-ляп особых знаний не требуется. Чаще задавай вопросы. ОП тут всем отвечает.
Господа, что можете подсказать по поводу CORS?
Проблема:
Есть api ems почтыроссии, результат хочу тянуть аяксом, но в итоге получаю хуй в виде "Политика одного источника запрещает чтение удаленного ресурса на блаблабла".
Конечно же, в htaccess прописал Access-Control-Allow-Origin "*", но это не помогло. МОжет ли быть, что я ещё где-то лоханулся?
Сейчас пытаюсь отфильтровать всё кроме русских букв.
Использую /[^А-Я]/
/ начало выражения
[^ любые символы в любом месте кроме
А-Я русских букв (не чувствительно к регистру)
]/ конец выражения
При таком раскладе всё работает, кроме букв Ё и ё.
Но при попытке добавить букву Ё всё летит к чертям и многие русские буквы заменяются квадратиками.
Подробности и код тут https://ideone.com/Gs7hPB
Может быть я неправильно формулирую? Мне нужно чтобы в конце концов получилось: не русские буквы и не буква ё
Но может ты всё таки глянешь, если не сложно.
https://github.com/NotBadCode/Upload
Подключать надо как тут.
http://hashcode.ru/questions/234843/php-slim-framework-%D0%BA%D0%B0%D0%BA-%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%82%D1%8C
И, почему не используешь composer. Удобней же.
>Подключать надо как тут.
Я подключил, но не пользую его там почти.
Только для страницы со скачкой.
Ага, так значит. А почему не в index.php?
Именно он должен всё обрабатываеть.
Понимешь, Слим из коробки дает тут роутер (штуку, которая разбирает URL на части и вызывает нужную функцию).
Это в index.php решается какую функцию запускать.
а как мне реализовать переход по ссылка?
через <a> или через гет запрос,
у меня вот это не получилось
Не понимаю в чём проблема. Мне нужно больше информации, где это у тебя не получается.
По ссылке переходишь на какой-то конкретный URL(кстати по какому ты адресу переходишь). И по этому самому URL определяешь какую функцию запускать, какие шаблоны выводить.
>>440877
Смотри вот у меня test.ru/upload
там запускается index.php
Когда я перехожу например на
test.ru/upload/file через <a>
у меня 404
Обработчик
$app->post('/:file', function ($id) use ($mapper){
$app->get('/:file', function ($id) use ($mapper){
Не запускается
Я ведь так должен делать?
И ещё апп-рендер можно только пхп-файл предавать?
$app->post('/:file', function ($id) use ($mapper){
:file - это переменная. Эта функция запустится если будет такой путь.
test.ru/upload/nevagno_cto_tut_napisano
$app->post('/file', function ($id) use ($mapper){
file - это путь. Эта функция запустится если будет такой и только такой путь.
test.ru/upload/file
Вроде всё должно у тебя работать. Лучше скидывай код на гитхабе, так удобней будет
Алсо, ты смог запустить тот пример с Hello World?
>Алсо, ты смог запустить тот пример с Hello World?
да
мой английский сосёт и я во всём путаюсь
Ты давай ссылку на твой код, без него сложно понять где именно проблема. Я не ОП, Талантом отгадывания проблем не владею.
Вроде разобрался с тем что было. Успел забыть, что http заголовки отправляются раньше любых других данных.
Сделал немного по другому.
https://github.com/tokotun/uppy/blob/master/uppy/app/functions.php#L25
Вот эта функция теперь делает уменьшенную копию картинки. И сохраняет под тем же именем с префиксом '_'.
Нужно ли в этой задаче обходится без дубликатов сохранённых картинок?
Если дубликаты не нужны. То у меня на примете только такой вариант: при каждом запуске удалят файлы с префиксом '_'.
Похаписты, халп! Репощу из соседнего джава-треда. Помогите гуманитариедауну решить простенький тест по регулярным выражениям. С меня нихуя.
1. Придумайте произвольное регулярное выражение, которому соответствует ровно 231 различная строка. Поясните свой ответ.
2. Придумайте строку, которая найдётся и по запросу [клмн](прст)?, и по запросу (клмн)?.
3. Придумайте регулярное выражение, которое будет находить арифметические выражения типа 6 * 4 = 24, 2+7=9, 141-15 = 126, 900 / 2=450
sic! пробелы так и должны быть
4. Сколько в файле alice.txt слов, которые начинаются и заканчиваются на одну и ту же букву (напр., alpha, deed, stops)? Опишите алгоритм поиска.
5. Сколько в файле alice.txt слов, которые начинаются на глухой согласный звук? Опишите алгоритм поиска.
Если используешь запрос к базе данных в функции, без globаl переменной не обойтись же? Не в каждой же функции писать подключение к базе данных.
Доказывает что REST это всего лишь подход и не надо с фанатизмом пытаться все реализовать идеально — некоторыми принципами можно и поступиться.
Судя по комментам, все на хую вертели этот REST и используют, как им удобно.
Ставить sidebar на li было необязательно. Гораздо лучше поставить только на ul и исплоьзовать
.sidebar { ... }
.sidebar > li { ... }
Так и писать меньше, и путаницы меньше.
id в стилях лучше не использовать, лучше использовать классы потому что классы в отличие от id могут повторяться и можно поставить несколько классов на элемент. То есть они удобнее.
> ul.sidebar{
> height:900px;
Это неправильно. Почему именно 900px? Откуда взялась эта цифра? Она добавляет большой пустой оступ снизу: http://jsfiddle.net/8xypLhot/12/
Кроме этих 900px, остальное верно.
>>440510
> Но есть вопрос, внутри функции fixText я хотел запихнуть регулярные выражения как $key и то, на что надо заменять результат поиска как $value в массив и пройти foreach, но чего-то не то оно делает, первый проход норм, а второй исправляет уже исправленное, причем непонятно по какой логике это делает, а вот так по отдельности все ок
Без примера кода трудно понять в чем дело. Покажи код.
> [ ]?+
А зачем тут ?+ Ты не опечатался? Добавление знака + к квантификатору это штука для оптимизации (описано тут в конце http://php.net/manual/ru/regexp.reference.repetition.php ). Ты ведь явно хотел что-то другое написать.
> [,]
Запятая не спецсимвол и его не надо брать в скобки. Список специсимволов вроде бы есть в уроке и есть в мануале: http://php.net/manual/ru/regexp.reference.meta.php
> [a-z|а-я]
В квадратных скобках | не имеет специального значения и обозначает символ вертикальной черты. Также, буква ё в регулярках не входит в диапазон а-я (так вышло) и ее надо писать отдельно.
Надо писать [a-zа-яё]
> if (($arr [$i] == "." | $arr [$i] == "!" |
Чтобы написать логическое «или» надо писать ||. Знак | обозначает двоичное побитовое ИЛИ и это совсем другая операция. Мануал:
http://php.net/manual/ru/language.operators.bitwise.php
http://php.net/manual/ru/language.operators.logical.php
> \tfor($i = 0; $i < (count ( $arr ) - 2); $i ++) {//первые символы оставшихся предложений в заглавную букву
Работать со строкой по символам довольно неудобно. Как посоветовал другой анон, через preg_replace_callback полуается гораздо проще, если ты знаешь эту функцию. Если нет то можно оставить цикл.
>>440693
Тут лучше переписать регулярку чтобы она самую первую букву тоже ловила, тогда не нужно будет громоздкое
> $res2 = mb_strtoupper(mb_substr($res2, 0, 1)) . mb_substr($res2, 1);
> задачу.
Вот
> Задание: дан неграмотно написанный текст, состоящий из нескольких предложений на русском языке. Ошибки заключаются в неправильной расстановке пробелов и отсутсвии заглавных букв. Исправить текст так, чтобы все предложения в нем начинались с большой буквы, а после знаков запятая, точка, восклицательный и вопросительный знак стоял ровно один пробел (а перед ними — ни одного).
Ставить sidebar на li было необязательно. Гораздо лучше поставить только на ul и исплоьзовать
.sidebar { ... }
.sidebar > li { ... }
Так и писать меньше, и путаницы меньше.
id в стилях лучше не использовать, лучше использовать классы потому что классы в отличие от id могут повторяться и можно поставить несколько классов на элемент. То есть они удобнее.
> ul.sidebar{
> height:900px;
Это неправильно. Почему именно 900px? Откуда взялась эта цифра? Она добавляет большой пустой оступ снизу: http://jsfiddle.net/8xypLhot/12/
Кроме этих 900px, остальное верно.
>>440510
> Но есть вопрос, внутри функции fixText я хотел запихнуть регулярные выражения как $key и то, на что надо заменять результат поиска как $value в массив и пройти foreach, но чего-то не то оно делает, первый проход норм, а второй исправляет уже исправленное, причем непонятно по какой логике это делает, а вот так по отдельности все ок
Без примера кода трудно понять в чем дело. Покажи код.
> [ ]?+
А зачем тут ?+ Ты не опечатался? Добавление знака + к квантификатору это штука для оптимизации (описано тут в конце http://php.net/manual/ru/regexp.reference.repetition.php ). Ты ведь явно хотел что-то другое написать.
> [,]
Запятая не спецсимвол и его не надо брать в скобки. Список специсимволов вроде бы есть в уроке и есть в мануале: http://php.net/manual/ru/regexp.reference.meta.php
> [a-z|а-я]
В квадратных скобках | не имеет специального значения и обозначает символ вертикальной черты. Также, буква ё в регулярках не входит в диапазон а-я (так вышло) и ее надо писать отдельно.
Надо писать [a-zа-яё]
> if (($arr [$i] == "." | $arr [$i] == "!" |
Чтобы написать логическое «или» надо писать ||. Знак | обозначает двоичное побитовое ИЛИ и это совсем другая операция. Мануал:
http://php.net/manual/ru/language.operators.bitwise.php
http://php.net/manual/ru/language.operators.logical.php
> \tfor($i = 0; $i < (count ( $arr ) - 2); $i ++) {//первые символы оставшихся предложений в заглавную букву
Работать со строкой по символам довольно неудобно. Как посоветовал другой анон, через preg_replace_callback полуается гораздо проще, если ты знаешь эту функцию. Если нет то можно оставить цикл.
>>440693
Тут лучше переписать регулярку чтобы она самую первую букву тоже ловила, тогда не нужно будет громоздкое
> $res2 = mb_strtoupper(mb_substr($res2, 0, 1)) . mb_substr($res2, 1);
> задачу.
Вот
> Задание: дан неграмотно написанный текст, состоящий из нескольких предложений на русском языке. Ошибки заключаются в неправильной расстановке пробелов и отсутсвии заглавных букв. Исправить текст так, чтобы все предложения в нем начинались с большой буквы, а после знаков запятая, точка, восклицательный и вопросительный знак стоял ровно один пробел (а перед ними — ни одного).
> Скажите, он очень костыльный?
да.
Глобальные переменные зло. Так как функция которая зависит только от переданных аругментов понятнее и предсказуемее.
Ты наверно хочешь спросить: неужели мне теперь надо в каждую функцию работы с БД передавать $con? Я отвечу: в случае исплоьзования функций, придется (либо придется пользоваться плохими глобальными переменными), в случае использования ООП такой проблемы нет. Хороший повод перейти на ООП, кстати.
> mysql_query
мануал читал? http://php.net/manual/ru/function.mysql-query.php — устарела функция
Сейчас используют либо PDO ( http://habrahabr.ru/post/137664/ ) либо MySQLi ( http://habrahabr.ru/post/119294/ ). У mysqli есть процедурный вариант, но лучше бы использовать ООП.
> WHERE id='$id'");
Это SQL инъекция. Не подставляй данные прямо в запрос, используй плейсхолдеры.
Ты явно по какому-то очень устаревшему учебнику учился. так сейчас уже никто не пишет.
Вот полезный сайт по теме: http://phptherightway.ru/
Ну и названия переменных ужасные, вроде row1. Почему 1? Почитай-ка статью: http://learn.javascript.ru/write-unmain-code
>А файл alice.txt мне откуда взять?
Нет такого файла, это абстрактный рандомный файл. Важно само регулярное выражение и алгоритм поиска.
Вообще хорошие книги по юзабилити это Алан Купер ( «Об интерфейсе» — большая) и «Психбольница в руках пациентов». А также Раскин «Интерфейс» (кстати, у меня они все есть в бумажной версии, а вот книг по программированию ни одной нет).
Но они объясняют общие принципы, вроде локуса внимания (пользователь смотрит в одну точку в один момент времени), подсчета числа действий и много других интересных вещей. Это скорее теория которая помогает понимать, почему делают так или иначе (после ее прочтения ты скорее всего сможешь смотреть на интерфейсы другими глазами). Также, там описывается подход к проектирование через определение задач и поведения пользователей. Книги реально полезные, если ты их не читал, советую прочесть.
Книги не про веб-приложения, а про юзабилити и и интерфейсы в общем. Но для конечного пользователя нет особой разницы между веб- и десктопным приложением.
С технической точки зрения различия есть, и довольно большие.
> то вот с тем, как это делают в вебе, я не знаком совсем.
Хорошо бы посмотреть какие-то существующие интерфейсы. Google Drive может быть?
Примеры дизайна можно найти на том же dribble: https://dribbble.com/search?q=interface
Если ты про набор виджетов, то в вебе нет какого-то стандартизованного набора (как например в WinAPI или Qt). Есть встроенные в браузер контролы, есть сторонние библиотеки виджетов вроде jQUery UI, Kendo UI, есть библиотеки реализующие один контрол вроде Chosen.
Также в плане реализации ты можешь делать клиент тоньше или толще, перенося меньше или больше логики в браузер с сервера. Тут тоже есть плюсы и минусы.
Проектировать интерфейс стоит начать с составления сценариев, какие задачи будут решать пользователи, и как им решить их быстрее и исходя из этого решать какие будут экраны, какие на них элементы с какими возможностями.
Получился довольно абстрактный совет, так что если есть уточняющие вопросы, задавай.
Это неправильно. Вообще, конечно система ошибок в php неудачная, лучше бы все на исключениях было.
>>440718
> Собственно у меня вопрос, session_start лучше писать непосредственно перед работой с этими переменными?
Пока ты не начнешь сессию, массив SESSION будет пустой.
Также, session_start должен стоять до начала вывода, так как он ставит куки, а куки это заголвоки, а заголовки должны идти до тела HTTP ответа.
> А если в начале скрипта, то нормально ли написать эту строчку в отдельном файле с другими штуками, который инклудится в начале каждого файла?
Нормально. Кстати, такой файл инициализации обычно называют bootstrap.php
>>440720
> Речь о том, что бы всю подобную копипасту разбросанную по файлам, написать в одном файле и инклудить его в начале каждого файла со скриптом.
так и надо сделать
> там вроде бы не рекомендовалось писать session_start в начале скрипта, а делать это только когда начинается работа с сессией непосредственно
Это экономия на спичках, если у тебя не миллионы посещений то это ничего не меняет.
>>440730
> Мне нужно так же хранить этот код в базе и возвращать нужного студента проверяя этот код?
да, код должен храниться в базе чтобы можно было его проверить и определить по нему о каком студенте речь.
По идее можно сделать и без сохранения в базу. Например, шифровать id, а при редактировании расшифровывать, но это намного сложнее получается. Зато без обращения к базе можно проверить правильность кода.
Прмитивный вариант шифрования это добавлять к id подпсиь вида
md5("длинный секретный пароль" . $id)
Но тут есть недостаток что при похищении одного пароля злоумышленник получает доступ ко всем аккаунтам, так как пароль один для всех.
Это неправильно. Вообще, конечно система ошибок в php неудачная, лучше бы все на исключениях было.
>>440718
> Собственно у меня вопрос, session_start лучше писать непосредственно перед работой с этими переменными?
Пока ты не начнешь сессию, массив SESSION будет пустой.
Также, session_start должен стоять до начала вывода, так как он ставит куки, а куки это заголвоки, а заголовки должны идти до тела HTTP ответа.
> А если в начале скрипта, то нормально ли написать эту строчку в отдельном файле с другими штуками, который инклудится в начале каждого файла?
Нормально. Кстати, такой файл инициализации обычно называют bootstrap.php
>>440720
> Речь о том, что бы всю подобную копипасту разбросанную по файлам, написать в одном файле и инклудить его в начале каждого файла со скриптом.
так и надо сделать
> там вроде бы не рекомендовалось писать session_start в начале скрипта, а делать это только когда начинается работа с сессией непосредственно
Это экономия на спичках, если у тебя не миллионы посещений то это ничего не меняет.
>>440730
> Мне нужно так же хранить этот код в базе и возвращать нужного студента проверяя этот код?
да, код должен храниться в базе чтобы можно было его проверить и определить по нему о каком студенте речь.
По идее можно сделать и без сохранения в базу. Например, шифровать id, а при редактировании расшифровывать, но это намного сложнее получается. Зато без обращения к базе можно проверить правильность кода.
Прмитивный вариант шифрования это добавлять к id подпсиь вида
md5("длинный секретный пароль" . $id)
Но тут есть недостаток что при похищении одного пароля злоумышленник получает доступ ко всем аккаунтам, так как пароль один для всех.
В чём может быть проблема?
> Эм, индексы я вообще не создавал, отложил это на попозже, и так и не сделал
Тормозить будет, без индексов любой поиск сводится к полному перебору коллекции, если в ней хотя бы сотня тысяч элементов, будет тяжело. Даже если меньше, все равно будет не быстро работать. Ну и неправильно говорить что ты знаешь монгу если ты не умеешь пользоваться индексами, по моему.
>Мне показалось они сами создаются, если их не существует, но ты в неё пишешь.
Если так то ок.
> Кстати где в коде это делать? Что, каждый раз при запуске PHP скрипта, проверять, есть ли нужные коллекции\индексы? Это же разовая процедура должна быть
Давай спросим гугл: http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=mongodb+index+source+control
Ничего не ищется. Печалька. Значит, надо писать велосипед. Видимо надо сделать php-скрипт который запускается из командной строки и делает вызовы ensureIndex в нужном количестве.
Еще есть такая утилита: https://github.com/brandonramirez/mongo-index-sync — но я ей не пользовался.
В любом случае, индексы должны быть в репозитории, а не где-то вне его.
> Это же разовая процедура должна быть
Проект развивается, индексы добавляются и удаляются. Никак не разовая.
> Тогда в серверной части в контейнере лежало бы куча всякого, ему вообще ненужного
пусть лежит, какая разница. Это же 2 части одного приложения, удобно когда любой сервис доступен из любой части приложения. И дублирование кода — нехорошо.
> Вот handler классы я изначально как раз и делал, для того, чтоб они кешировали обьекты RoomUser и RoomEvent, чтоб не было повторных обращений к БД
Это (identity map) делается не столько для кеширования, сколько для поддержания абстракции. ORM/ODM создают абстракцию, как будто бы никакой базы нет и все объекты хранятся у нас в памяти (в абстрактном репозитории). Такая абстракция позволяет писать код проще, так как мы не должны вообще думать о хранилище и его особенностях. Ну и когда один пользователь соответствует ровно одному (а не нескольким объектам) тоже проще получается.
Если ты будешь изучать Doctrine 2 (она входит в симфони), то со всем этим столкнешься.
> у нас есть два "писателя" в БД, server и webapp, Соответственно, Webapp что то поменял в коллекции RoomUser - как RoomUserHandler в Server части об этом узнает?
Как решение, можно после обработки каждого websocket-события очищать identity map.
> Сначала думал, что можно будет обойтись "малой кровью" - простым счетчиком заходов юзера в отдельную комнату. Типа юзер зашел - увеличиваем.
ой-ой, это же очень тяжело отлаживать, и потерять единичку тоже легко.
> А значит webapp-соединение должно быть совместимо в server-соединением - в общем тут надо подумать, как грамотно сделать.
При загрузке страницы сервер генерирует ей id сеанса. Вторая вкладка в браузере — второй id. Она передает его во всех ajax запросах. Его можно и в heartbeater исплоьзовать кстати. И в вебсокете тоже.
Эта проблема кстати есть и в мессенджерах: при заходе с нескольких устройств куда слать сообщения? В джаббере есть приоритеты, где-то шлют на последнее подключенное/активное устройство, где-то на все сразу.
> Возможно вообще реализовать аналог WAMP
Это усложнение наверно. Мне кажется хватит id сеанса.
> это из за того, что если мы сделаем new MongoId('some_custom_string') - будет ошибка.
Мануал вроде объясняет: http://php.net/manual/ru/class.mongoid.php
> Каждый MongoId состоит из 12 байт (преобразующихся в 24 шестнадцатеричных символа).
А то что ты делаешь какие-то костыли. Заметь что тут http://php.net/manual/ru/mongoid.construct.php видно что при создании объекта он сам генерирует новый id. У меня есть подозрения что класс MongoId это класс для генерации или хранения сгенерированных id и если он тебе не нравится то можно просто им не пользоваться.
Если ты не хочешь использовать 12 байтовый формат то наверно можно просто не исплоьзовать MongoId, а передавать свой id строкой (или нельзя? наверняка можно).
> Эм, индексы я вообще не создавал, отложил это на попозже, и так и не сделал
Тормозить будет, без индексов любой поиск сводится к полному перебору коллекции, если в ней хотя бы сотня тысяч элементов, будет тяжело. Даже если меньше, все равно будет не быстро работать. Ну и неправильно говорить что ты знаешь монгу если ты не умеешь пользоваться индексами, по моему.
>Мне показалось они сами создаются, если их не существует, но ты в неё пишешь.
Если так то ок.
> Кстати где в коде это делать? Что, каждый раз при запуске PHP скрипта, проверять, есть ли нужные коллекции\индексы? Это же разовая процедура должна быть
Давай спросим гугл: http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=mongodb+index+source+control
Ничего не ищется. Печалька. Значит, надо писать велосипед. Видимо надо сделать php-скрипт который запускается из командной строки и делает вызовы ensureIndex в нужном количестве.
Еще есть такая утилита: https://github.com/brandonramirez/mongo-index-sync — но я ей не пользовался.
В любом случае, индексы должны быть в репозитории, а не где-то вне его.
> Это же разовая процедура должна быть
Проект развивается, индексы добавляются и удаляются. Никак не разовая.
> Тогда в серверной части в контейнере лежало бы куча всякого, ему вообще ненужного
пусть лежит, какая разница. Это же 2 части одного приложения, удобно когда любой сервис доступен из любой части приложения. И дублирование кода — нехорошо.
> Вот handler классы я изначально как раз и делал, для того, чтоб они кешировали обьекты RoomUser и RoomEvent, чтоб не было повторных обращений к БД
Это (identity map) делается не столько для кеширования, сколько для поддержания абстракции. ORM/ODM создают абстракцию, как будто бы никакой базы нет и все объекты хранятся у нас в памяти (в абстрактном репозитории). Такая абстракция позволяет писать код проще, так как мы не должны вообще думать о хранилище и его особенностях. Ну и когда один пользователь соответствует ровно одному (а не нескольким объектам) тоже проще получается.
Если ты будешь изучать Doctrine 2 (она входит в симфони), то со всем этим столкнешься.
> у нас есть два "писателя" в БД, server и webapp, Соответственно, Webapp что то поменял в коллекции RoomUser - как RoomUserHandler в Server части об этом узнает?
Как решение, можно после обработки каждого websocket-события очищать identity map.
> Сначала думал, что можно будет обойтись "малой кровью" - простым счетчиком заходов юзера в отдельную комнату. Типа юзер зашел - увеличиваем.
ой-ой, это же очень тяжело отлаживать, и потерять единичку тоже легко.
> А значит webapp-соединение должно быть совместимо в server-соединением - в общем тут надо подумать, как грамотно сделать.
При загрузке страницы сервер генерирует ей id сеанса. Вторая вкладка в браузере — второй id. Она передает его во всех ajax запросах. Его можно и в heartbeater исплоьзовать кстати. И в вебсокете тоже.
Эта проблема кстати есть и в мессенджерах: при заходе с нескольких устройств куда слать сообщения? В джаббере есть приоритеты, где-то шлют на последнее подключенное/активное устройство, где-то на все сразу.
> Возможно вообще реализовать аналог WAMP
Это усложнение наверно. Мне кажется хватит id сеанса.
> это из за того, что если мы сделаем new MongoId('some_custom_string') - будет ошибка.
Мануал вроде объясняет: http://php.net/manual/ru/class.mongoid.php
> Каждый MongoId состоит из 12 байт (преобразующихся в 24 шестнадцатеричных символа).
А то что ты делаешь какие-то костыли. Заметь что тут http://php.net/manual/ru/mongoid.construct.php видно что при создании объекта он сам генерирует новый id. У меня есть подозрения что класс MongoId это класс для генерации или хранения сгенерированных id и если он тебе не нравится то можно просто им не пользоваться.
Если ты не хочешь использовать 12 байтовый формат то наверно можно просто не исплоьзовать MongoId, а передавать свой id строкой (или нельзя? наверняка можно).
>Отображает информацию о проходах сотрудника
Если имеется в виду какой-то турникет, к которому сотрудник прикладывает магнитную карту и фиксируются его проходы, это очень проблематично. Я неправильно понял?
Вообще, на этой задаче все споыткаются.
Ответ должен быть около 61270. Там в учебнике специально дан код с ошибкой, и надо ее исправить (или написать с нуля без ошибки).
> if ($creditBalance < 1000) {
Это неуниверсальное решение, так как ты его сделал под частный случай. Почему именно 1000? Если мы поменяем сумму или условия кредита, оно перестанет работать.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
>>440748
Я кстати придумал еще кое-что, что можно улучшить. У тебя сейчас приложение не масштабируется. твой демон однопоточный и он не может задействовать больше 1 ядра процессора. А ведь на серверах обычно стоят 16-64 ядерные системы , да и самих серверов может быть много. Но твой демон можно запустить только в 1 экземпляре и рано или поздно он упррется в нехватку CPU. Соответственно, задачей могло бы было сделать масштабируемый демон, который можно запускать в N экхемплярах, и клиенты бы случайно или как-то еще выбирали один из них.
Это если тебе интересна тема высоких нагрузок, масштабирование (но прежде чем за это браться надо разобраться с индексами и тестами производетельности).
> ну это все копипаста из заготовленных шаблонов
Надо хотя бы понимать что копипастишь
> Нуу... там написано что очередь можно повесить на любой обьект.
Тут явно лучше сделать очередь отдельным свойством так как неизвестно какие она свойства добавляет в объект, да и вообще бардак какой-то получается, объект одновременно и объект и очередь.
> а во вторых щас немного не до этого: работаю джуном и ищу работу на позицию мидла, так что можешь скрестить за меня пальцы - твои уроки не проходят даром.
Ну ясно. Удачи тогда. Это кстати хороший пример другими анонам был бы.
Вообще, на этой задаче все споыткаются.
Ответ должен быть около 61270. Там в учебнике специально дан код с ошибкой, и надо ее исправить (или написать с нуля без ошибки).
> if ($creditBalance < 1000) {
Это неуниверсальное решение, так как ты его сделал под частный случай. Почему именно 1000? Если мы поменяем сумму или условия кредита, оно перестанет работать.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
>>440748
Я кстати придумал еще кое-что, что можно улучшить. У тебя сейчас приложение не масштабируется. твой демон однопоточный и он не может задействовать больше 1 ядра процессора. А ведь на серверах обычно стоят 16-64 ядерные системы , да и самих серверов может быть много. Но твой демон можно запустить только в 1 экземпляре и рано или поздно он упррется в нехватку CPU. Соответственно, задачей могло бы было сделать масштабируемый демон, который можно запускать в N экхемплярах, и клиенты бы случайно или как-то еще выбирали один из них.
Это если тебе интересна тема высоких нагрузок, масштабирование (но прежде чем за это браться надо разобраться с индексами и тестами производетельности).
> ну это все копипаста из заготовленных шаблонов
Надо хотя бы понимать что копипастишь
> Нуу... там написано что очередь можно повесить на любой обьект.
Тут явно лучше сделать очередь отдельным свойством так как неизвестно какие она свойства добавляет в объект, да и вообще бардак какой-то получается, объект одновременно и объект и очередь.
> а во вторых щас немного не до этого: работаю джуном и ищу работу на позицию мидла, так что можешь скрестить за меня пальцы - твои уроки не проходят даром.
Ну ясно. Удачи тогда. Это кстати хороший пример другими анонам был бы.
Нашёл решение. Регексп должен быть в виде /[^А-Я]/u, чтобы нормально работать с utf8.
>. В итоге получается долга 5100 и за последний месяц его выплатить не удается
Потому лучше разбить это все на 2 действия:
- банк начисляет проценты и увеличивает долг
- анон выплачивает либо сколько может (если долг большой) либо сколько осталось (если маленький)
А не в одну строку все писать, как у тебя тут:
> $creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
>>440778
> Вот такую конструкцию я имел в виду.
Ты посмотри откуда ты берешь текст и куда кладешь:
> $res1 = preg_replace ( $wrong, $right, $text );
Так всегда в res1 будет толбко результат последдней замены.
Надо просто чуть переменные поменять.
>>440780
> 6 задача
Заменчания тут есть: >>440961 так как 900px ты убрал, то в общем задача решена.
> 7 зачада
> Кстати, в жсфиддле пришлось высоту другую указывать, в хроме у меня почему-то когда 30 пикселей указываешь, то высота блока такой и будет.
А ты читал примеания к задаче? По историческим приинам часть элементов форм использует box-sizing: border-box, а часть content-box. Причем исплоьзует уже лет 15 или больше, когда этого свойства еще в помине не было, а разница уже была. Я помню как лет 5 назад сам делал исследование в разных браузерах и обнаружил этот эффект (в интернете информации особо не было, пришлось опытным путем проверять. В стандарте куда я заглянул в первую очередь написано что на элементы форм правила CSS не распространяются).
Потому ты должен либо учитывать и ставить разную высоту либо использовать box-sizing (c префиксами чтобы охватить больше браузеров).
Почему у тебя в Хроме этого эффекта нет — не знаю. Может просто не так заметна разница?
В фаерфоксе элементы не выравниваются вертикально, один выше другого на пару пикселей. vertical-align исправляет проблему.
Вообще, элементы форм это конечно боль. Вот еще в ФФ например надпись на кнопке находится не по центру, а ниже. Паддинг может быть виноват.
>. В итоге получается долга 5100 и за последний месяц его выплатить не удается
Потому лучше разбить это все на 2 действия:
- банк начисляет проценты и увеличивает долг
- анон выплачивает либо сколько может (если долг большой) либо сколько осталось (если маленький)
А не в одну строку все писать, как у тебя тут:
> $creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
>>440778
> Вот такую конструкцию я имел в виду.
Ты посмотри откуда ты берешь текст и куда кладешь:
> $res1 = preg_replace ( $wrong, $right, $text );
Так всегда в res1 будет толбко результат последдней замены.
Надо просто чуть переменные поменять.
>>440780
> 6 задача
Заменчания тут есть: >>440961 так как 900px ты убрал, то в общем задача решена.
> 7 зачада
> Кстати, в жсфиддле пришлось высоту другую указывать, в хроме у меня почему-то когда 30 пикселей указываешь, то высота блока такой и будет.
А ты читал примеания к задаче? По историческим приинам часть элементов форм использует box-sizing: border-box, а часть content-box. Причем исплоьзует уже лет 15 или больше, когда этого свойства еще в помине не было, а разница уже была. Я помню как лет 5 назад сам делал исследование в разных браузерах и обнаружил этот эффект (в интернете информации особо не было, пришлось опытным путем проверять. В стандарте куда я заглянул в первую очередь написано что на элементы форм правила CSS не распространяются).
Потому ты должен либо учитывать и ставить разную высоту либо использовать box-sizing (c префиксами чтобы охватить больше браузеров).
Почему у тебя в Хроме этого эффекта нет — не знаю. Может просто не так заметна разница?
В фаерфоксе элементы не выравниваются вертикально, один выше другого на пару пикселей. vertical-align исправляет проблему.
Вообще, элементы форм это конечно боль. Вот еще в ФФ например надпись на кнопке находится не по центру, а ниже. Паддинг может быть виноват.
Покажи код, я напишу что не так и что исправить. задачи ведь ты решаешь для себя, чтобы лучше научиться программировать, а с готовыми решениями твой мозг ничему не научится.
>>440835
Сложно, так как тебе фактически надо выучить php, базы данных, HTML/CSS.
>>440845
> Почему? Да потому что.
Потому что он давно устарел может быть? Причем им кроме просторов бывшего СССР особо и не пользуются нигде.
>>440855
Есть еще книги по всему сразу вроде Р. Никсон "Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript и CSS". Книга в общем весьма сомнительная так как примеры кода плохие, много устаревшией информации, код с ошибками и уязвимостяим. Но если ты не собираешься быть программистом, а просто надо сделать задание и забыть и никогда в жизни ничего не писать на php то может тебе подойдет.
Но вообще, я не уверен что ты сделаешь. Ты готов каждый день по несколько часов все это учить? Ты скорее всего забьешь и бросишь на полпути.
>>440858
> Конечно же, в htaccess прописал Access-Control-Allow-Origin
Прописывать должен не ты, а почта России. Если не прописывают значит не одобряют такой вид запросов. И если это API то наверно оно рассчитано на вызовы с сервера?
Ну и вообще кстати, писать такие вещи как ты прописал довольно опасно. Это может привести к уязвимостям вроде XSRF на твоем сайте.
>>440864
- букву ё надо указывать отдельно: а-яё
- почему нет флага u в регулярке? У тебя какая кодировка? в utf-8 флаг u обязателен .
Если что мой урок на тему utf-8 и строк: https://gist.github.com/codedokode/ff99e357e9860ea169b8
>>440867
Подключать Слим конечно лучше бы через композер было. В таком случае в репозитории только твой код и ничего лишнего. И обновлять проще.
То, что у тебя конечно не подойдет. Я вообще не вижу в index.php где Слим используется. Да он и не исплоьзуется вообще.
Идея Slim в том что у тебя один файл index.php и роутингом (определением что надо делать в зависимости от URL и метода) занимается фреймворк. Я писал выше как должен выглядеть код: >>439909 надо сделать примерно так, без файлов list.php, file.php.
Ну и добавить .htaccess который перенаправляет все запросы к несуществующим файлам на index.php
Покажи код, я напишу что не так и что исправить. задачи ведь ты решаешь для себя, чтобы лучше научиться программировать, а с готовыми решениями твой мозг ничему не научится.
>>440835
Сложно, так как тебе фактически надо выучить php, базы данных, HTML/CSS.
>>440845
> Почему? Да потому что.
Потому что он давно устарел может быть? Причем им кроме просторов бывшего СССР особо и не пользуются нигде.
>>440855
Есть еще книги по всему сразу вроде Р. Никсон "Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript и CSS". Книга в общем весьма сомнительная так как примеры кода плохие, много устаревшией информации, код с ошибками и уязвимостяим. Но если ты не собираешься быть программистом, а просто надо сделать задание и забыть и никогда в жизни ничего не писать на php то может тебе подойдет.
Но вообще, я не уверен что ты сделаешь. Ты готов каждый день по несколько часов все это учить? Ты скорее всего забьешь и бросишь на полпути.
>>440858
> Конечно же, в htaccess прописал Access-Control-Allow-Origin
Прописывать должен не ты, а почта России. Если не прописывают значит не одобряют такой вид запросов. И если это API то наверно оно рассчитано на вызовы с сервера?
Ну и вообще кстати, писать такие вещи как ты прописал довольно опасно. Это может привести к уязвимостям вроде XSRF на твоем сайте.
>>440864
- букву ё надо указывать отдельно: а-яё
- почему нет флага u в регулярке? У тебя какая кодировка? в utf-8 флаг u обязателен .
Если что мой урок на тему utf-8 и строк: https://gist.github.com/codedokode/ff99e357e9860ea169b8
>>440867
Подключать Слим конечно лучше бы через композер было. В таком случае в репозитории только твой код и ничего лишнего. И обновлять проще.
То, что у тебя конечно не подойдет. Я вообще не вижу в index.php где Слим используется. Да он и не исплоьзуется вообще.
Идея Slim в том что у тебя один файл index.php и роутингом (определением что надо делать в зависимости от URL и метода) занимается фреймворк. Я писал выше как должен выглядеть код: >>439909 надо сделать примерно так, без файлов list.php, file.php.
Ну и добавить .htaccess который перенаправляет все запросы к несуществующим файлам на index.php
То есть что я хочу сказать? Фреймворк тем и отличается от библиотеки что это основа (каркас) приложения. Он задает структуру приложения. если в Слиме принято писать роуты в index.php значит надо их там и описывать.
Так что не сдавайся, давай разберем что у тебя не работает и в итоге все таки добьемся чтобы оно заработало.
Насчет композера, это пока можно оставить как есть, но позже надо переделать на исплоьзование композера. Найди время для этого. Если что-то работать не будет, пиши, я посмотрю. Если ты что-то не понимаешь, напиши что именно.
По поводу английского и документации, попробуй перевести в bing translator — он технические тексты относительно читабельно переводит: http://www.microsofttranslator.com/bv.aspx?from=&to=ru&a=http%3A%2F%2Fdocs.slimframework.com%2F%23Getting-Started
Да и там весь мануал читать не требуется, только то что ты исплоьзуешь.
Еще, я там написал много замечаний. Их надо либо все исправить либо как-то отреагировать, например написать что «это непонятно» или «это и так нормально сделано».
>>440871
А надо использовать. Slim это фреймворк и он каркас приложения.
>>440879
> Когда я перехожу например на
> test.ru/upload/file через <a>
> у меня 404
Ты файл .htaccess добавил? Покажи-ка его. По умолчанию Апач пытается найти папку upload/file и с помощью htaccess мы заставляем его вместо этого вызвать index.php где запустится Слим и вызовет нашу функцию.
> И ещё апп-рендер можно только пхп-файл предавать?
Можно не php но он просто выведется как есть. расширение и имя файла не важны, важно что в нем.
Я бы тебе советовал в этой задаче использовать не шаблоны на php, а освоить шаблонизатор twig. Он удобный и современный (используется в symfony 2, вдохновлен питоновским jinja) и полезно его знать.
То есть что я хочу сказать? Фреймворк тем и отличается от библиотеки что это основа (каркас) приложения. Он задает структуру приложения. если в Слиме принято писать роуты в index.php значит надо их там и описывать.
Так что не сдавайся, давай разберем что у тебя не работает и в итоге все таки добьемся чтобы оно заработало.
Насчет композера, это пока можно оставить как есть, но позже надо переделать на исплоьзование композера. Найди время для этого. Если что-то работать не будет, пиши, я посмотрю. Если ты что-то не понимаешь, напиши что именно.
По поводу английского и документации, попробуй перевести в bing translator — он технические тексты относительно читабельно переводит: http://www.microsofttranslator.com/bv.aspx?from=&to=ru&a=http%3A%2F%2Fdocs.slimframework.com%2F%23Getting-Started
Да и там весь мануал читать не требуется, только то что ты исплоьзуешь.
Еще, я там написал много замечаний. Их надо либо все исправить либо как-то отреагировать, например написать что «это непонятно» или «это и так нормально сделано».
>>440871
А надо использовать. Slim это фреймворк и он каркас приложения.
>>440879
> Когда я перехожу например на
> test.ru/upload/file через <a>
> у меня 404
Ты файл .htaccess добавил? Покажи-ка его. По умолчанию Апач пытается найти папку upload/file и с помощью htaccess мы заставляем его вместо этого вызвать index.php где запустится Слим и вызовет нашу функцию.
> И ещё апп-рендер можно только пхп-файл предавать?
Можно не php но он просто выведется как есть. расширение и имя файла не важны, важно что в нем.
Я бы тебе советовал в этой задаче использовать не шаблоны на php, а освоить шаблонизатор twig. Он удобный и современный (используется в symfony 2, вдохновлен питоновским jinja) и полезно его знать.
> ужно ли в этой задаче обходится без дубликатов сохранённых картинок?
Уменьшенные картинки разумеется можно создавать и сохранять. Только имя лучше дать понятное например
thumb-(имяфайла)
или
thumbs/filename.jpg
А ты все файлы в одну папку кладешь? Что если загрузить 2 файла с одинаковым именем но разным содержимым?
По коду, быстро проглядел:
> src="uppy/container/_{{ file.key }}
Ты в шаблон помещаешь логику определения имени превьюшки. Неправильно. Должна быть функция или метод.
> {% if isImage == true %}
Это удобно сделать методом у File наверно? Мы же ООП используем. {% if file.isImage() ...
> {{ file.size }} байт
Вывел бы лучше в человекопонятном виде вроде 16,5 Мб
> href="{{ hostName }}/download/{{ file.key }}"
Тут наверно лучше сделать где-то еще функцию или метод для получения ссылки на скачивание.
> <a class="brand" href='{{ hostName }}/main'>UPPY</a>
Обычно эта ссылка ведет на главную. Непонятно почему она разная в разных шаблонах.
В форме поиска надо добавить кнопку. Я не уверен что без кнопки она вообще будет отправляться.
> https://github.com/tokotun/uppy/blob/master/uppy/app/File.php#L22
Вот это точно не там должно быть. У нас File представляет собой информацию о файле и он не должен выводить какие-то заголовки, что-то там отдавать в браузер, мне кажется. Для этого должен быть внешний метод или функция, а у тебя класс File и швец, и жнец, и на дуде игрец.
> header('Content-Disposition: attachment; filename=' . $this->name);
для опции filename разрешено исплоьзовать только латиннциу (ASCII если точнее). русские буквы разные браузеры понимают поразному. Лучше не используй эту опцию вообще.
> ORDER BY dateLoad DESC
Индекс по dateLoad сделал? А то mysql будет в память выкачивать всю таблицу файлов и сортирвоать (ты бы мог сказать что никто тебя этому не учил; что поделать, учись: http://www.mysql.ru/docs/man/ORDER_BY_optimisation.html )
Без индекса на большой таблице файлов разница будет большая, порядка 2 мс против 2 секунд например на таблице с сотней тысяч файлов.
> https://github.com/tokotun/uppy/blob/master/uppy/app/FileMapper.php#L34
> public function loadFile($key)
Нет проверки если в базе нет такой записи.
> $file->dateLoad = $result['dateLoad'];
Я думаю, удобно при загрузке из БД преобразовать дату из mysql в php формат. А при вставке делать обратное.
> https://github.com/tokotun/uppy/blob/master/uppy/app/functions.php#L2
> function getErrorLoad
Это называется статический конструктор и делается статическим методом на классе ErrorLoad, такие функции обыно называются createX или fromX: http://php.net/manual/ru/language.oop5.static.php
> function createFile($errorLoad)
нужен тайп-хинт. Тайп хинты делают твой код понятнее и намного надежнее. Используй их.
Вообще, функции из functions (создание файла и создание превьюшки) можно бы вынести в класс Uploader.
>>440901
Если тебе дать готовый ответ, ты ничего не выучишь. Изучи регулярныйе выражения, задания-то простые.
> ужно ли в этой задаче обходится без дубликатов сохранённых картинок?
Уменьшенные картинки разумеется можно создавать и сохранять. Только имя лучше дать понятное например
thumb-(имяфайла)
или
thumbs/filename.jpg
А ты все файлы в одну папку кладешь? Что если загрузить 2 файла с одинаковым именем но разным содержимым?
По коду, быстро проглядел:
> src="uppy/container/_{{ file.key }}
Ты в шаблон помещаешь логику определения имени превьюшки. Неправильно. Должна быть функция или метод.
> {% if isImage == true %}
Это удобно сделать методом у File наверно? Мы же ООП используем. {% if file.isImage() ...
> {{ file.size }} байт
Вывел бы лучше в человекопонятном виде вроде 16,5 Мб
> href="{{ hostName }}/download/{{ file.key }}"
Тут наверно лучше сделать где-то еще функцию или метод для получения ссылки на скачивание.
> <a class="brand" href='{{ hostName }}/main'>UPPY</a>
Обычно эта ссылка ведет на главную. Непонятно почему она разная в разных шаблонах.
В форме поиска надо добавить кнопку. Я не уверен что без кнопки она вообще будет отправляться.
> https://github.com/tokotun/uppy/blob/master/uppy/app/File.php#L22
Вот это точно не там должно быть. У нас File представляет собой информацию о файле и он не должен выводить какие-то заголовки, что-то там отдавать в браузер, мне кажется. Для этого должен быть внешний метод или функция, а у тебя класс File и швец, и жнец, и на дуде игрец.
> header('Content-Disposition: attachment; filename=' . $this->name);
для опции filename разрешено исплоьзовать только латиннциу (ASCII если точнее). русские буквы разные браузеры понимают поразному. Лучше не используй эту опцию вообще.
> ORDER BY dateLoad DESC
Индекс по dateLoad сделал? А то mysql будет в память выкачивать всю таблицу файлов и сортирвоать (ты бы мог сказать что никто тебя этому не учил; что поделать, учись: http://www.mysql.ru/docs/man/ORDER_BY_optimisation.html )
Без индекса на большой таблице файлов разница будет большая, порядка 2 мс против 2 секунд например на таблице с сотней тысяч файлов.
> https://github.com/tokotun/uppy/blob/master/uppy/app/FileMapper.php#L34
> public function loadFile($key)
Нет проверки если в базе нет такой записи.
> $file->dateLoad = $result['dateLoad'];
Я думаю, удобно при загрузке из БД преобразовать дату из mysql в php формат. А при вставке делать обратное.
> https://github.com/tokotun/uppy/blob/master/uppy/app/functions.php#L2
> function getErrorLoad
Это называется статический конструктор и делается статическим методом на классе ErrorLoad, такие функции обыно называются createX или fromX: http://php.net/manual/ru/language.oop5.static.php
> function createFile($errorLoad)
нужен тайп-хинт. Тайп хинты делают твой код понятнее и намного надежнее. Используй их.
Вообще, функции из functions (создание файла и создание превьюшки) можно бы вынести в класс Uploader.
>>440901
Если тебе дать готовый ответ, ты ничего не выучишь. Изучи регулярныйе выражения, задания-то простые.
REST это подход при разработке API и приложений. Он упомниается например тут: http://habrahabr.ru/post/38730/
Главные принципы такие:
- использование URL для того чтобы представить какой-то ресурс. Ну например URL /users/10 может соответсвовать пользователю с id = 10 и разные методы вроде GET/POST/PATCH/PUT/DELETE исплоьзуются для операций над этим пользователем
Если ты не понимаешь что такое URL, метод то тебе стоит сначала изучить HTTP, так как REST обычно реализуется на нем.
- остутсвие состояния на сервере. Это значит что например для выполнения какого-то действия надо сделать один запрос, а не несколько (подготовить данные для обновления, обновить данные). Соответственно, нежелательно использовать штуки вроде сессий, кук в API.
Отстутсиве состояние упрощает масштабирование сервиса на несколько узлов, перезапуск и т.д.
Заметь что это лишь общие принципы и не более.
На этом вроде бы все. Ты можешь посмотреть на примеры реализации разных API, например яндекс-диск: https://tech.yandex.ru/disk/api/concepts/about-docpage/
>>440979
А где схема таблицы (команда CREATE TABLE в которой описаны типы полей)? Может у тебя типы полей не те?
Ну и может, ты просто 2 раза вызываешь функцию вставки.
Код кстати плохой. Там куча сомнительных мест. И использование статических методов это не ООП, а процедурный код. И класс у тебя занимается и работой с БД, и очисткой POST параметров.
REST это подход при разработке API и приложений. Он упомниается например тут: http://habrahabr.ru/post/38730/
Главные принципы такие:
- использование URL для того чтобы представить какой-то ресурс. Ну например URL /users/10 может соответсвовать пользователю с id = 10 и разные методы вроде GET/POST/PATCH/PUT/DELETE исплоьзуются для операций над этим пользователем
Если ты не понимаешь что такое URL, метод то тебе стоит сначала изучить HTTP, так как REST обычно реализуется на нем.
- остутсвие состояния на сервере. Это значит что например для выполнения какого-то действия надо сделать один запрос, а не несколько (подготовить данные для обновления, обновить данные). Соответственно, нежелательно использовать штуки вроде сессий, кук в API.
Отстутсиве состояние упрощает масштабирование сервиса на несколько узлов, перезапуск и т.д.
Заметь что это лишь общие принципы и не более.
На этом вроде бы все. Ты можешь посмотреть на примеры реализации разных API, например яндекс-диск: https://tech.yandex.ru/disk/api/concepts/about-docpage/
>>440979
А где схема таблицы (команда CREATE TABLE в которой описаны типы полей)? Может у тебя типы полей не те?
Ну и может, ты просто 2 раза вызываешь функцию вставки.
Код кстати плохой. Там куча сомнительных мест. И использование статических методов это не ООП, а процедурный код. И класс у тебя занимается и работой с БД, и очисткой POST параметров.
Надо писать ё отдельно: а-яё так как в юникоде она идет не в середине алфавита, а отдельно: http://unicode-table.com/ru/#cyrillic
Не понял. Вот у нас есть сайт с профилями, каждый профиль получаем благодаря гет переменной ?user, это что REST сервис?
Ой-ой, а это что такое?
> $loader->add('app\\FileMapper\\', __DIR__);
Это надо не в коде, а в composer.json описать:
https://getcomposer.org/doc/04-schema.md#autoload
http://habrahabr.ru/post/149678/
> return $fileMapper = new \Uppy\FileMapper($pdo);
Переменная не нужна тут
> 'cache' => dirname(__FILE__) . '/vendor/twig/cache',
По моему не очень удачный выбор так как vendor это папка для сторонних библиотек, а не временнных файлов. Лучше сделать папку типа tmp, cache и подобную. И закрыть в нее доступ через htaccess.
> \tresizeImage($file->key, $app->config('uploadPath'));
Это надо делать один раз, а не при каждом просмотре страницы.удобно делать при загрузке или при первом обращении к странице.
> $file->fileForceDownload($app->config('dirHost'));
Скачивание лучше бы реализовать без участия php так как Апач отдает файлы горазло быстрее и с меньшим потреблением ресурсов. Но вознимает проблема как указать имя файла? Параметр filename не годится, потому остается только один вариант: имя должно быть в URL в конце, например:
/download/10/file.txt
Второй вопрос как сделать чтобы файл отдавал Апач?
- можно с помощью php только начинать загрузку и передавать ее Апачу с помощью X-Sendfile (нужен модуль mod_sendfie): http://habrahabr.ru/post/151795/
- можно вообще обойтись без php, сделав правило в htaccess что при обращении к URL вида /download/10/... надо отдавать файл с именем files/10.dat
И еще один момент. Когда ты делаешь загрузку файлов всегда есть риск что тебе закачают на сервер:
— php-скрипт
— htaccess файл изменяющий настройки Апача с целью выполнить какой-нибудь файл как php
Соответственно злоумышленник получает полный контроль над сервером.
Ты от этого защищен? Ты отключил выполнение php скриптов в папке загрузок? Ты меняешь расширение при сохранении?
Ой-ой, а это что такое?
> $loader->add('app\\FileMapper\\', __DIR__);
Это надо не в коде, а в composer.json описать:
https://getcomposer.org/doc/04-schema.md#autoload
http://habrahabr.ru/post/149678/
> return $fileMapper = new \Uppy\FileMapper($pdo);
Переменная не нужна тут
> 'cache' => dirname(__FILE__) . '/vendor/twig/cache',
По моему не очень удачный выбор так как vendor это папка для сторонних библиотек, а не временнных файлов. Лучше сделать папку типа tmp, cache и подобную. И закрыть в нее доступ через htaccess.
> \tresizeImage($file->key, $app->config('uploadPath'));
Это надо делать один раз, а не при каждом просмотре страницы.удобно делать при загрузке или при первом обращении к странице.
> $file->fileForceDownload($app->config('dirHost'));
Скачивание лучше бы реализовать без участия php так как Апач отдает файлы горазло быстрее и с меньшим потреблением ресурсов. Но вознимает проблема как указать имя файла? Параметр filename не годится, потому остается только один вариант: имя должно быть в URL в конце, например:
/download/10/file.txt
Второй вопрос как сделать чтобы файл отдавал Апач?
- можно с помощью php только начинать загрузку и передавать ее Апачу с помощью X-Sendfile (нужен модуль mod_sendfie): http://habrahabr.ru/post/151795/
- можно вообще обойтись без php, сделав правило в htaccess что при обращении к URL вида /download/10/... надо отдавать файл с именем files/10.dat
И еще один момент. Когда ты делаешь загрузку файлов всегда есть риск что тебе закачают на сервер:
— php-скрипт
— htaccess файл изменяющий настройки Апача с целью выполнить какой-нибудь файл как php
Соответственно злоумышленник получает полный контроль над сервером.
Ты от этого защищен? Ты отключил выполнение php скриптов в папке загрузок? Ты меняешь расширение при сохранении?
В принципе может быть да, но красивее сделать URL вида
/profile/:id
Ну и если сессии и куки используются то тоже как-то не REST.
Все же в GET параметрах указываются дополнительные какие-то опции, например какие подробности нужны про юзера, а ид юзера должен быть в uRL. Чтобы у каждого юзера был свой URL.
Тогда получается у каждого юзера своя страница, то бишь отдельный файл на сервере?
URL не обязан соответсовать файлам один-к-одному. Ты можешь настроить сервер так чтобы при обращении к любому URL вида /user/xxx вызывался один и тот же файл, например user.php.
Для nginx это делается через правило location, для Апаа через mod_rewrite.
Обычно при работе на фреймворке просто пишут правило что любые обращения перенаправлять на index.php, какой бы не был URL.
Скажи пожалуйста подробнее про сомнительность кода. Не знал куда засунуть эти методы. Метод очистки $_POST, методы получения/отправки данных в БД, потом ещё методы для Cookies появятся, и что-нибудь ещё с шифрованием данных. Для удобства сделал их принадлежащими классу user, чтобы под ногами не валялись. Методы статические, пока не знаю для чего в этом случае делать конструктор (ведь при переходе на другой php-скрипт состояние класса User будет теряться).
Про CREATE TABLE не знаю, подробнее почитаю про SQL, буду разбираться.
>Если тебе дать готовый ответ, ты ничего не выучишь. Изучи регулярныйе выражения, задания-то простые.
Дружище, я вообще на филологическом, и бог с ним, что не выучу, мне бы только зачет сдать и забыть, как страшный сон. Да я и сам вижу, что простые, в иных условиях задрочил бы теорию и сам сделал, но на мне другие зачеты висят, а время поджимает. Помогите, аноны, вы же сечете, для вас это как алфавит.
статические методы = процедурный код, а не ООП. Со статическими методами ты не можешь создать несколько экземпляров класса с разными настройками, не можешь подсунуть один класс вместо другого, в общем это не код, а процедурная лапша поулчается. Ты не можешь использовать ни одного преимущества ООП.
Ну и дело не только в преимуществах. «Правильный» код быстрее понять, проще исправить и поддерживать. С ним приятнее работать.
Вот мой урок немного имеющий отнощение к теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
Вот урок про способы в ООП работать с базой: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
> ведь при переходе на другой php-скрипт состояние класса User будет теряться
Верно, но это не повод отказываться от ООП.
> Метод очистки $_POST
это тоеж в общем неправильный подход. Зачем его очищать? Если пользователь ввел что-то неправильно лучше показать ему форму и предложить исправить ошибки, а не вбивать в базу непонятно что
> Не знал куда засунуть эти методы.
Каждый класс должен заниматься своим делом. Класс работы с БД умеет вставлять пользователей в базу, но не знает ничего про POST и очистку данных, класс работы с POST умеет работать с ним, но не умеет с базой, и тд.
> Про CREATE TABLE не знаю, подробнее почитаю про SQL, буду разбираться.
Как ты таблицу создал не зная? Как вообще с базой работать не зная SQL? Если через phpmyadmin то там должна быть опция показать схему таблицы или как-то так, или можно дамп сделать и в нем посмотреть.
Вообще, ты сначала должен изучать SQL а потом браться за визуальные инструменты вроде phpmyadmin. Вот тут есть ссылки на неплохие туториалы для начинающих: https://gist.github.com/codedokode/10539213
Например вот это:
http://phpclub.ru/mysql/doc/tutorial.html
http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html (проходить надо с первой части)
Еще, настройки работы с БД не должны быть в коде, обычно их выносят в config.php чтобы легко было поменять. Класс работы с БД не должен сам коннектитья к базе а должен получать объект PDO например через конструктор, это гарантирует что его не забудут передать.
unset не нужен, он там ничего не делает. Локальные переменные и так удаляются при выходе из фукнкции.
В общем, хороший класс это как инструмент. тебе надо забить гвоздь ты берешь молоток и забиваешь им гвоздь. Аналогично с ООП, ты хочешь сохранить юзера — ты создаешь объект класса для сохранения и сохраняешь:
$mapper = new UserMapper($pdo);
$mapper->save($user);
при этом этот класс занимается только сохранением, не лезет в POST, ничего не очищает и вообще ничего не делает о чем его не просили. Это хороший класс так как ты можешь с его помощью сохранить любого юзера (не обязательно переданного через POST) в любую базу данных.
статические методы = процедурный код, а не ООП. Со статическими методами ты не можешь создать несколько экземпляров класса с разными настройками, не можешь подсунуть один класс вместо другого, в общем это не код, а процедурная лапша поулчается. Ты не можешь использовать ни одного преимущества ООП.
Ну и дело не только в преимуществах. «Правильный» код быстрее понять, проще исправить и поддерживать. С ним приятнее работать.
Вот мой урок немного имеющий отнощение к теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
Вот урок про способы в ООП работать с базой: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
> ведь при переходе на другой php-скрипт состояние класса User будет теряться
Верно, но это не повод отказываться от ООП.
> Метод очистки $_POST
это тоеж в общем неправильный подход. Зачем его очищать? Если пользователь ввел что-то неправильно лучше показать ему форму и предложить исправить ошибки, а не вбивать в базу непонятно что
> Не знал куда засунуть эти методы.
Каждый класс должен заниматься своим делом. Класс работы с БД умеет вставлять пользователей в базу, но не знает ничего про POST и очистку данных, класс работы с POST умеет работать с ним, но не умеет с базой, и тд.
> Про CREATE TABLE не знаю, подробнее почитаю про SQL, буду разбираться.
Как ты таблицу создал не зная? Как вообще с базой работать не зная SQL? Если через phpmyadmin то там должна быть опция показать схему таблицы или как-то так, или можно дамп сделать и в нем посмотреть.
Вообще, ты сначала должен изучать SQL а потом браться за визуальные инструменты вроде phpmyadmin. Вот тут есть ссылки на неплохие туториалы для начинающих: https://gist.github.com/codedokode/10539213
Например вот это:
http://phpclub.ru/mysql/doc/tutorial.html
http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html (проходить надо с первой части)
Еще, настройки работы с БД не должны быть в коде, обычно их выносят в config.php чтобы легко было поменять. Класс работы с БД не должен сам коннектитья к базе а должен получать объект PDO например через конструктор, это гарантирует что его не забудут передать.
unset не нужен, он там ничего не делает. Локальные переменные и так удаляются при выходе из фукнкции.
В общем, хороший класс это как инструмент. тебе надо забить гвоздь ты берешь молоток и забиваешь им гвоздь. Аналогично с ООП, ты хочешь сохранить юзера — ты создаешь объект класса для сохранения и сохраняешь:
$mapper = new UserMapper($pdo);
$mapper->save($user);
при этом этот класс занимается только сохранением, не лезет в POST, ничего не очищает и вообще ничего не делает о чем его не просили. Это хороший класс так как ты можешь с его помощью сохранить любого юзера (не обязательно переданного через POST) в любую базу данных.
На филологическом изучают программирование на Яве? ты серьезно? Что за специальность? Тебе не кажется что правильнее пойти в деканат и потребовать отменить этот маразм, ты же не на матфаке?
В голосище.
Здесь, да.
Для начала прочитай вот эту штуку внимательно. Задачи можешь и не решать.
http://archive-ipq-co.narod.ru/l1/regexp.html
Просто поймешь синтаксис своих регулярок.
Спасибо, вроде годный мануал. Хоть и времени в обрез, придется, видимо, обмазываться этими вашими регулярными выражениями. Хотя они у меня бубноватые какие-то получаются.
Сейчас я тебе помогу. Просто после мануала ты и сам сможешь решить пару заданий оттуда. Я вот не могу в первое въехать. Какое-то условие не очень внятное
Так вот и я не особо просекаю. Вообще там было еще два задания, но их я вроде и так сделал, может, и проверите заодно:
1. Какой из этих шаблонов не является правильным регулярным выражением? Выберите верный ответ и поясните его.
(А) [фывапр][1-7]
(Б) [ПРСТУ])
(В) ([0-36])
(Г) п|р
Ответ: Б d'uh
2. В какой строке текста жадный запрос и.и и ленивый запрос и.?и найдут одну и ту же подстроку ненулевой длины? Выберите верный ответ и поясните его.
(А) Александр Сергеевич Пушкин\t
(Б) Михаил Юрьевич Лермонтов
(В) Анна Андреевна Ахматова
(Г) Марина Ивановна Цветаева
Ответ: А, подстрока в результате: «ич Пушки». В варианте Б жадный запрос найдет «ихаил Юрьеви», ленивый – «ихаи»; в вариантах В и Г оба запроса найдут пустую строку (так как в В нет букв «и», а в Г вторая «и» в верхнем регистре).
А дальше я уже перестал въезжать. То есть, синтаксис-то этот понимаю, и примерно представляю, как делать, но как доходит до составления выражения, начинаю путаться в квантификаторах и прочей ебалде. В итоге может получиться какая-то хуерга на три строчки, которую можно было бы оптимизировать до 5-10 символов.
Блджад, опять астериски теряются, глупая макаба.
Пиздец я такой пост накатал, а он не пускает его. В ПОСТЕ ЕСТЬ СЛОВО ИЗ СПАМ ЛИСТА Охуеть блядь, ебал в рот Абу.
Вот пока скрины о которых речь в посте.
А сам пост http://pastebin.com/Dn5CrAbu лови.
Спасибо, доброанон! В принципе, у меня что-то похожее получалось, хотя меня пугали длинные формулы. Альзо, насколько я понимаю, alice.txt - англоязычный файл (судя по 4-му заданию), но подправить тут будет не проблема.
Кидай Яндекс, дружище, оплачу тебе завтрак.
>>441054
Я ошибся
Во втором задании ответ: нет такой строки
потому что
[клмн](прст)? ищет одну из букв из первых скобок, далее либо всю вторую скобку, либо нихуя.
А вот (клмн)? ищет либо клмн целиком, либо нихуя, так что я не знаю какие у них пересечения, скорее всего не существует таких. Но то что я тебе там написал, явно неправильный ответ.
Да, у меня тоже такая мысль проскочила, но я как-то пока забил на это задание, с другими разбирался. А вообще да, не будет тут совпадений. Я так понимаю, ответ "пустая строка" будет? Или он и пустую не найдет? Не совсем этот момент понимаю.
>>441065
Печально. Все равно спасибо, я хоть как-то продвинулся. Если вдруг озарение насчет остальных заданий придет - точно вознагражу!
По первому заданию тебе нужно что-то типа кастрированной регулярки валидации айпишника вхерачить. Но если там ищет 256 различных вариантов, то тут надо сделать поменьше. Например напишем выражение, которое ищет числа от 0 до 230.
Получим как раз 231 различных строк.
Чем я, по-твоему, занимаюсь до пяти утра? Сорян, что я не задрачивал ЯП и околоЯПную теорию годами, а теперь мне прилетает такая плюха в виде экзамена по регулярам. Теорию задрочил уже вдоль и поперек, готовые выражения могу разбирать, но как до составления собственных выражений доходит, нихуя не получается. Мог бы сам решить, вот уж на харкач бы не обращался.
Не сразу дошло, но это же вообще нехуй делать тогда. Я строки в традиционном смысле рассматривал просто, поэтому даже не подумал об этом. Вот потому и нечего гуманитариеблядкам программирование навязывать.
С ее помощью можно найти слова, которые заканчиваются и начинаются на ту же букву (а если добавить рекурскию, можно вообще палиндромы искать).
Так же pcre умеет разбирать более сложные грамматики, но это уже статья для программистов, а не филологов: http://habrahabr.ru/post/171667/
\d если его нету в нужном диалекте заменяется на [0-9]
Не троль, я же разобрался с этим уже, и тебе спасибо, агрессивный погромист.
>>441081
>>441085
Не знаю, не знаю насчет диалектов. У нас же не какой-то определенный ЯП, да и программирования как такового нет, сугубо регулярные выражения, вырванные из контекста. Уместно ли будет использовать выражение, работающее только в определенном диалекте? Да и вообще я глянул, там больше из программирования всяких "флагов", "подмасок", пустые слова для меня. Неужели нет какого-то традиционного способа такую задачу решить? Чтобы выражение в любом языке и диалекте работало.
Получается, совсем нет решения. Препод троллит меня? Вопрос-то стоит "придумайте строку.."
В регулярных выражениях есть так называемые диалекты. Фактически есть несколько видов синтаксиса. То есть в основном они похожи, но некоторые фичи в некоторых диалектах отстутсвуют или пишутся по другому.
Так как тут php тред то мы используем диалект pcre, а если у тебя другой диалект (наверняка другой) то какие-то вещи может быть надо подправить или заменить.
Но базовые вещи вроде точки, вертикальной черты, плюса, звездочки везде общие.
> там больше из программирования всяких "флагов", "подмасок", пустые слова для меня
Подмаски это то что в круглых скобках.
Флаги это особенности pcre — в твоем диалекте их может не быть.
Но у меня нет никакого конкретного языка, и вообще программирования нет. Просто тест по регулярным выражениям, блджад. Я не совсем представляю, как это должно выглядеть и под что я должен "изменять". Я думал, они типа общие и одинаковые для всех.
У тебя должны были быть какие-то лекции или методички или учебник. Посмотри какие конструкции объясняются там и используй только те которые там были.
В регулярных вражениях есть общий синтаксис, а есть некоторые коснтрукции которые не везде можно использовать.
Ну скобки, звезочки и точки везде работают.
Ну смотри, (клмн)?.* значит, что у тебя в начале строки стоит или не стоит клмн, а потом стоит точка, которая обозначает любой символ кроме переноса строк, и далее звездочка, которая говорит, что этих любых символов может быть от 0 до бесконечности. По факту любая строка подходит под эту регулярку. То есть тебе осталось придумать строку которая подходит под вторую регулярку: [клмн](прст)? а она читается так:
одна из букв к л м н обязательно, и возможно сочитание прст
стало быть все возможные ответы
1. к
2. кпрст
3. л
4. лпрст
5. м
6. мпрст
7. н
8. нпрст
Не было нихуя. Короче, было 6 или 8 занятий, на которые я не ходил, но по рассказам одногруппников он на них ни слова о РВ не говорил, показывал презентации по истории машинного перевода и прочую чушь. Потом дал экзамен (этот тест), сказал, открывайте википедию или что хотите там и делайте задания. Вот как-то так. Сам экзамен я тоже проебал, поэтому теперь тот же тест пишу заочно.
Да, звучит логично, спасибо.
>>441099
>любой диалект который тебе нравится
Хэлоу? Я позавчера узнал, что такое регулярные выражения. Мне никакой диалект не нравится, потому что я ни одного не знаю, мое представление о программировании ограничивается ПРИВЕТ МИР в паскале в 9-м классе.
В общем, хуй с ним, с заданием этим, тащемта все остальные практически решены, думаю, на зачет наскребу. Не стоит оно того.
под
> используй любой диалект который тебе нравится.
он имел в виду:
Используй то, что мы тебе тут нарешали и не выебывайся. С теми объяснениями которые приложены к ответам я бы защитил эту хуету на 5, инфа 100%
Ну и вообще, судя по твоим объяснениям, я тебе рекомендую прост забирать доки с вуза и идти заниматься чем-то более полезным. Нахуя ты там тратишь своё время? Если на платном учишься, то тем более шли нахуй. Ты же понимаешь, что ты как бесполезный долбоеб по факту, если:
>Короче, было 6 или 8 занятий, на которые я не ходил...
>Сам экзамен я тоже проебал.
Ты не знаний не получаешь, не социализацией не занимаешься там. Нормальный человек либо сам бы все решил, либо за счет одногрупников. Вот не в обиду сказано, просто сам такой же хуйней страдал в вузе, и если бы мог вернуть время назад, то дропнул бы всё еще в зародыше, как только начал скатываться. Сейчас вот сижу учусь сам, лол.
Вот прост расскажи мне, чем ты занимаешься всё время?
>пришел на двач ты
>хочешь советов мудрых
А я все ждал, когда же начнется разбор меня, моего вуза и моей жизни. Уж волноваться начал, не ошибся ли я бордой. Не беспокойся, дружище, свою жизнь я как-нибудь налажу, спасибо за заботу.
Спасибо всем откликнувшимся, спасли брата-анона от возможного отчисления из-за ненужного говнопредмета. Даже агрессивному илиткопогромисту спасибо, что снизошел-таки до моего уровня и даже соизволил пообщаться со мной на понятном мне языке (не программирования). Вы няши.
Ну может грубо сказано, но это лишь реакция на твои манеры. Это же все не наши проблемы, что ты проебывал пары и не учился. А когда ты еще и оправдываешь своё незнание материала этим, то выглядишь как полный долбоеб. По факту я просто попросил тебя рассказать о том, чем ты в жизни занимаешься? Сколько времени ты чему уделяешь. Это просто общением называется. К тому же когда тебе уже помогли, ответ на этот вопрос был бы хорошим тоном, вместо шаблонных вскукарекиваний про двач.
Ладно тебе, если анон не хочет, пусть не расказывает.
>не выебывайся
>я тебе рекомендую прост забирать доки с вуза
>Ты же понимаешь, что ты как бесполезный долбоеб по факту
>Это просто общением называется
Это называется лезть в чужую жизнь и делать выводы по буквально двум словам (он сказал что проебал 6 занятий информатики, ебать он бесполезный отброс еще и на платном стопроц вообще нахуй тебе образование дропай и иди на заводы будешь полезным я лучше знаю как тебе жить). Ну или у тебя какое-то странное представление об общении.
Я пришел за помощью с недопредметом, с этим маленьким шестичасовым прыщом на теле моей любимой специальности, помощь мне оказали, я поблагодарил добрых анонов и изволил откланяться. А ты мне вслед сыплешь какие-то никому не нужны советы, как мне жить и на кого мне учиться, глупый, глупый анон, ну неужели ты правда думаешь, что я не смогу сам свою судьбу устроить?
Неужели ты правда думаешь, что я буду сидеть в 6 утра в похапе треде и рассказывать анонимусам историю своей жизни? Ты какой-то странный, суриасли.
Пиздец, чет мне тебя даже жалко стало, бедный, зашуганный технарь, который к рандомным анонам на дваче с жизненными советами пристает. Ну может ты тогда свою историю расскажешь?
Так, ты тоже успокойся. Идите в другой раздел грустные истории рассказывать ок?
Сэр есть сэр мистер босс сэр админ генерал сэр!!
>>441118
Ты же говорил, что тебе как будто больше нечего делать, кроме как тут сидеть в 6 утра.
Там либо нечего рассказывать толком, либо дохуя. В итоге что то не нужно, что это. Не стану кукарекать про то, что у меня жизненного опыта больше, но просто я уже закончил учиться 2 года назад, на подобной специальности: Информатика в экономике называлась, и сейчас понимаю, что лучше бы я те 5.5 лет, которые я там потратил, занимался совсем другими вещами. Просто сначала я был мамкиным корзиноидом, который не знал что ему по жизни делать, вот и пошел в вуз. А когда ты курсе на 3 понимаешь, что это тебе и нахуй не нужно, и ничему ты уже не учишься, и не делаешь. А если и хочешь взяться за учебу, то ты охуеть как отстаешь от программы, то с другой стороны как бы жалко дропать, ведь уже столько времени и сил проебано на это. И с каждым семестром эта яма становится все глубже. ДА И МАМКУ НЕ ХОЧЕТСЯ РАССТРАИВАТЬ. В общем так и мучался последние пару лет, занимаясь хуйней полной. А после того как получил диплом, понимаешь что ты по факту у разбитого корыта. Вот и спрашиваю у тебя, не занимаешься ли ты тем же чем и я? Ведь если ты поступил, то нужно либо учиться, либо дропать. Ну или знакомства заводить полезные, которые тебе помогут в жизни. А бухать или ебашить в дотан с одногрупниками днями напролет, можно и без УЧЕБЫ В ВУЗЕ
Стереотипы-стереотипчики. Без обид, но я должен это сказать: да пошел ты на хуй со своими выводами, нихуя не знаешь ведь, пидорасина такая. хаха бухать дотан с одногруппничками, хули ты о моей жизни знаешь?
>когда ты курсе на 3 понимаешь, что это тебе и нахуй не нужно
Да что ты говоришь? Высшее образование не нужно? И ты это только к третьему курсу понял?
>учиться в универе
>actually ходить на занятия и слушать совковых преподов
Ох лол. Универ - последнее место, где тебе могут дать знания.
И что ты к информатике приебался? Она была у нас три недели, я вообще в хуй не тарабаню, зачем ее нам поставили. Разумеется, я на нее не ходил, какие знания мне там дадут? Я-то ценю свое время ну да, расписываюсь тут перед рандомным хуем.
Бля, да ты же школьник до сих пор. Который себя умнее других считает. Охуеваю с тебя. Встал в агрессивную позу после того как я твою детскую злобную сучью мразотную душенку задел парой нелестных фраз, ты должен был быть готов к этому и срет теперь вместо диалога. Ну как хочешь, можешь дальше выебываться, я не против.
Это уже твои комплексы похоже.
Бедный, бедный технарик. Как же хуево вам живется. Ну ты это, шторку иногда открывай, на улицу там выходи, что ли. Попробуй хотя бы с раза в месяц начать. Глядишь, через пару лет реабилитурешься, на людей кидаться перестанешь, в общение научишься. Жаль, жаль, конечно, зверьков.
А ты и все продолжаешь срать, причем сагрившись на то, что я якобы сделал выводы по двум словам о твоей жизни, ты делаешь так же выводы о моей. Но ты еще и пытаешься злобно тралить, дешевыми приемами, а я с тобой спокойно ведь разговариваю, иду на диплог, про себя немного рассказал. Тебя правда так ужалило? Или ты просто неудовлетворенность жизненную на меня пытаешься выместить?
Джииз, ты и правда животное необучаемое. А говорят, у технарей с логикой все в порядке. Пора сделать то, что собирался еще два часа назад - откланяться, спасибо за помощь, аноны, извините за этого полоумного, поднасрали здесь чуток.
Ты даже не понимаешь, что ты со мной тут беседуешь уже 5 часов, и благодаришь меня же, при этом на меня же агришься.
Если то как подготовить и выполнить INSERT в принципе разобрался:
$stmt = $mysqli->prepare("INSERT INTO users(user_login, user_password) VALUES (?, ?)");
$stmt->bind_param("ss", $login, $password);
$stmt->execute();
- как то так в упрощенном виде.
То вот как провернуть это с SELECT непонятно. Как мне получить результат моего селекта после того как я пишу:
\tif (!($stmt = $mysqli->prepare("SELECT user_id, user_login, user_password FROM users WHERE user_login = ?"))) {
\t echo "Не удалось подготовить запрос: (" . $mysqli->errno . ") " . $mysqli->error;
\t}
\tif (!$stmt->bind_param("s", $login)) {
\t echo "Не удалось привязать параметры: (" . $stmt->errno . ") " . $stmt->error;
\t}
\tif (!$stmt->execute()) {
\t echo "Не удалось выполнить запрос: (" . $stmt->errno . ") " . $stmt->error;
\t}
что дальше то должно быть?
Вроде разобрался.
В упрощенном виде сделал так:
$stmt = $mysqli->prepare("SELECT user_id, user_login, user_password FROM users WHERE user_login = ?");
$stmt->bind_param("s", $login);
$stmt->execute();
$queryResult = $stmt->get_result();
$dbData = $queryResult->fetch_assoc();
Всё работает вроде, всё правильно сделал?
Ты всё еще тут? ВЕРНУЛСЯ НА МЕСТО ПРЕСТУПЛЕНИЯ? Не собирался я никого тралить.
>>440991
Спасибо ананасы, я все осознал. Вообще пугает в погромировании то, что залепишь что-нибудь вроде [ ]?+ в регулярке, а в голове даже не шевельнется что это косяк. Только когда со стороны носом ткнут. И главное непонятно, чем ты думаешь когда косячишь, потому как очевидную ересь делаешь.
очень нуб
Извините за сажу.
Спасибо большое за развернутый ответ.
Про эти книги слышал, но как-то всё никак руки не доходили их прочитать. Наверное, сейчас пора начать.
И спасибо в особенности за dribbble.com, это как раз то, что мне нужно было, там нашел примеры того, как можно некоторые желаемые вещи сделать.
Я даже не знаю с чего начать.
>Ты файл .htaccess добавил?
вуп нет
Как его правильно создать?
У меня под виндой не создаётся файл без имени
>>439189
>Код по моему с ошибкой. Ты после битвы не восстанавливаешь состояние героев, в частности здоровье. Правильным решением будет клонировать героев и драться каждый раз новыми клонами (мануал: http://php.net/manual/ru/language.oop5.cloning.php ).
Не совсем понял как пользоваться клонированием.
http://ideone.com/2vMcQV
Вот в моем коде я при создании объекта Game в конструкторе клонирую 2 объекта Hero, помещаю сами объекты в свойство Game - $heroes, а клонированных в $cloned; дальше в ходе 20 раундов оба основных объекта класса Hero изменяют значение свойства $health, посл е игры я пытаюсь присвоить $this->heroes = $this->cloned; но это не работает и в свойстве $heroes остаются те же объекты что и остались после 20 раундов.
http://php.net/manual/ru/language.types.object.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
http://docs.slimframework.com/
Найди там раздел 'Apache and mod_rewrite'.
Мне бы по сути вопроса, голая информация сложно воспринимается без примеров, прочитаю и забуду.
Но там же задача уже начата.
Создай класс отделов. Создай классы работников. По ним создай объекты.
Потом создавай методы по расчёту их оплаты.
Если с этим проблемы. То прочитай про обьекты и задавай вопросы.
http://php.net/manual/ru/language.types.object.php
Предыдущую без департаментов то решил?
Переделал немного и поставил количество повторений вместо 1000 - 10, и работает вроде верно
http://ideone.com/gu2xOt
да там не сложно, берёшь пхп биндинг к openGL и делаешь.
http://sourceforge.net/projects/phpopengl/
Всё, нашел сам, оказывается дело не в клонировании было - у меня просто return стоял выше в одной из управляющих конструкций и в большинстве случаев функция не выполнялась до места где совершалась замена .
Спасибо за советы
>Это SQL инъекция. Не подставляй данные прямо в запрос, используй плейсхолдеры.
А если я фильтрую специальной написанной для этого функцией, и выглядит это примерно так:
$id = clearInt ($_GET["id"]);
Так тоже будет SQL-инъекция?
Смотря что это за функция.
Все нюансы фильтрования ты можешь и не учесть.
PDO удобней и надёжней будет. Там ни чего сложного.
Ты же фильтруешь не в oneFile() а где-то в другом месте. Как ты можеь гарантировать что не вызовешь эту функцию без фильтрации? Фильтровать надо прямо в функции. Ну и это все равно костыльный подход, есть плейсхолдеры которые специально придуманы для вставки данных в запрос, зачем ты пытаешься изобрести обходной путь?
Во всех языках кроме php данные вставляются через плейсхолдеры. Просто некоторые авторы учебников сами неграмотные, не разбираются ни в php ни в программировании и людей неправильному учат. В новых статьях и учебниках уже так никто не делает.
Ты не клонируешь ничего. Объекты отличаются от других типов данных тем что передаются по ссылке. Это значит что когда ты делаешь
$a = new Y( );
$b = $a;
То ты в $b копируешь ссылку на тот же самый объект, а не клонируешь его. У тебя по прежнему один объект на который ссылаются 2 переменных.
И это сделано специально, в 99% случаев требуется именно такое поведение. Но тебе такое не подходит. Ведь фактиески ты вторую битву проводишь не героями со свежими силами, а теми что остались после первой, причем один из них скорее всего уже мертвый. Потому надо клонировать героев и отправлять на битву клонов.
Клонирование объектов надо делать явно, оператром clone.
Мануал:
http://php.net/manual/ru/language.oop5.references.php
http://php.net/manual/ru/language.oop5.cloning.php
Есть код:
<?php
\tinclude ("db.php");
\t$dan = $_POST["dan"]; // передаем переменной $dan значение глобального массива POST
\t$sql = "INSERT INTO table1(text) VALUES('$dan')";
\t$zaprSQL = "SELECT * FROM table1";
\t$rezs = mysql_query($zaprSQL);
\twhile ($row = mysql_fetch_array($rezs)) {
\t\techo $row['text'] . "<br />";
\t}
?>
По идее он выполняет соединение с базой, записывает в таблицу введенное в форме значение и выводит все записи этой таблицы. Работает, но выводит он мне все записи, кроме той, которую я только что добавил. Не пойму, что не так делаю.
Да, верно. Заметь еще что там у mysqli_result есть метод fetch_all если тебе надо получить не одну строку, а все: http://php.net/manual/ru/mysqli-result.fetch-all.php
Еще одна вещь с которой ты должен разобраться это вывод ошибок от MySQL. Попробуй выполнить неправильный запрос (напрмер 'SELECT ASDFGGGG') и убедись что ты видишь сообщение об ошибке. Если ты его не видишь то плохо, ведь ты не сможешь нормально отлаживать код.
В упрощенном виде ты зря убрал if, как я понимаю, без них сообщение не выведется. Видимо mysqli требует после каждого действия проверять результат.
Ну и еще, наверно есть библиотеки поверх mysqli которые позволяют писать меньше кода, сами проверяют наличие ошибок и тд.
Не беда, пости свои решения, мы все проверим.
>>441204
Код покажи и на чем завис.
Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:
— какие есть сущности, для которых мы сделаем классы? (Сотрудник и Департамент)
— какие у них есть свойства (у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например мы хотим узнать сколько сотрудник заработал или сколько он пьет кофе. От департамента мы наверно хотим получить сколько всего выпито кофе и заплачено денег.
— как сущности связаны? Очевидно, Сотрудник работает в каком-то Департаменте.
Также, сразу скажу еще один совет: гораздо удобнее сделать не один класс Сотрудник, а 4 класса: Инженер, Менеджер, и т.д. Тогда мы можем легко менять например правила расчет зарплаты или кофе для каждой профессии. Естественно, копипастить одинаковый код в 4 класса не надо — создай базовый абстрактный класс Сотрудник и унаследуй от него 4 класса-профессии.
Наследование позволяет создавать класс не с нуля. а расширяя сущетсвующий класс: http://php.net/manual/ru/language.oop5.inheritance.php
«Абстрактный» — это класс, объект которого нельзя создать. Он предназначен для наследования от него других классов: http://php.net/manual/ru/language.oop5.abstract.php
Неделя. Но я ни где не работал. Ни где не учился. И вообще ни чем не был занят. Хотя между задачками в дотку гонял.
Было бы меньше свободного времени, то наверно месяц бы ушёл. Да, я ленивый хуй.
Хотя вспомнил, это я простенькие задачки на PHP делал неделю.
Это без задачек на HTML и CSS. И кошек мышек.
> У меня под виндой не создаётся файл без имени
Сначала я хотел сказать, что у меня плохие новости: если ты не можешь справиться с созданием файла без имени, то тебе будет тяжело программировать.
Но потом я попробовал создать файл средствами винды и он действительно не создается! И даже кавычками проблему не решить. Но выход все же есть.
Во-первых, можно в редакторе создать новый файл и сохранить его под любым именем (Sublime Text точно позволяет это). Во-вторых, можно погуглить: http://stackoverflow.com/questions/5004633/how-to-manually-create-a-file-with-a-dot-prefix-in-windows-for-example-htacce
В-третьих можно использовать консоль как подсказал анон.
Сам я пользуюсь Total Commander и потому с такой проблемой никогда не сталкивался (но не рекомендую использовать эту программу: она платная, она несвободная, она старая и пора бы ее закопать уже).
>>441248
Может тебе поможет мануал для начинающих: https://gist.github.com/codedokode/10539568
>>441249
Тебе не нужен redirect. Нужен rewrite который описан тут и эту статью ты явно даже не пробовал читать, верно? http://habrahabr.ru/company/sprinthost/blog/129560/
Спасибо.
Код очень запутанный. Надо его упрощать.
То, что относится к герою должно быть в его классе. То, что не относится, не должно.
Например у героя должен быть метод takeDamage. Ты не должен снаружи лезть и менять какие-то свойства, это логика героя и он сам должен с ней разбираться.
метод isAlive тоже должен быть у героя, а не у игры. Это же герой живой или нет, а не игра. И у него не должно быть аргументов. Ты просто вызываешь isAlive и получаешь ответ, жив ли еще герой или уже нет (можно просто проверять равен ли HP нулю как я понимаю, если равен то мертв).
> if ($hero->isChance($hero->crit)) {
Опять же ты занимаешься не своим делом. Должен быть просто метод isCriticalHit() и все.
> public function getHit($k) //
Здесь ты неудачно выбрал параметр функции. Почему число? У нас же ООП. Передавай сразу объекты, кто и кого бьет:
getDamage(Hero $attacker, Hero $target)
Смотри, какая хорошая и понятная функция получилась.
> public function isDoubleHit($k)
То же самое, лучше передавать в функцию героев
> if ($win == 0) {
> $first++;
Как-то запутанно. Не проще ли так?
1 — победил первый
2 - второй
0 - никто
Ну или вообще, возвращать объект героя-победителя или null при ничье.
Ну и названия лучше бы поменять слегка:
getGame -> runBattle
getRound -> runRound
Код очень запутанный. Надо его упрощать.
То, что относится к герою должно быть в его классе. То, что не относится, не должно.
Например у героя должен быть метод takeDamage. Ты не должен снаружи лезть и менять какие-то свойства, это логика героя и он сам должен с ней разбираться.
метод isAlive тоже должен быть у героя, а не у игры. Это же герой живой или нет, а не игра. И у него не должно быть аргументов. Ты просто вызываешь isAlive и получаешь ответ, жив ли еще герой или уже нет (можно просто проверять равен ли HP нулю как я понимаю, если равен то мертв).
> if ($hero->isChance($hero->crit)) {
Опять же ты занимаешься не своим делом. Должен быть просто метод isCriticalHit() и все.
> public function getHit($k) //
Здесь ты неудачно выбрал параметр функции. Почему число? У нас же ООП. Передавай сразу объекты, кто и кого бьет:
getDamage(Hero $attacker, Hero $target)
Смотри, какая хорошая и понятная функция получилась.
> public function isDoubleHit($k)
То же самое, лучше передавать в функцию героев
> if ($win == 0) {
> $first++;
Как-то запутанно. Не проще ли так?
1 — победил первый
2 - второй
0 - никто
Ну или вообще, возвращать объект героя-победителя или null при ничье.
Ну и названия лучше бы поменять слегка:
getGame -> runBattle
getRound -> runRound
Да, верно, там в документации есть готовый файл. А в статье на хабре можно прочесть и понять как это работает (работает просто: если идет обращение по URL который не соответствует никакму файлу, вызвать index.php)
>>441288
Исправь замечания, которые я написал выше. Пока у тебя не правильный ООП код, а просто функции случайно по классам разбросаны.
>>441320
Вот это как раз пример неправильно кода. зачем делать strip_tags при вставке в БД? БД никаких проблем от вставки html тегов не испытывает.
Явно его писал человек который в php не разбирается (и в узявимостях) и который просто все функции которые знал собрал вместе.
Ну и
> mysql_real_escape_string
Устарела
Кстати, strip_tags не защищает на 100% от XSS. Например если есть код
<?php
$value = strip_tags($_GET['value']);
?>
<input value="<?= $value ?>">
То тут возможна XSS если в $value вставить
" onfocus="скрипт" autofocus
>>441330
> Работает, но выводит он мне все записи, кроме той, которую я только что добавил.
Скорее всего она не добавилась из-за ошибки потому и не выводится. У тебя включен вывод ошибок? Если нет то очень плохо, как ты вслепую угадаешь в чем причина?
Также, код ужасен.
В коде у тебя SQL инъекция :
https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0
http://forum.antichat.ru/thread43966.html
Данные в запрос надо вставлять через плейсхолдеры:
http://habrahabr.ru/post/148701/
Если статья или учебник вставляет данные напрямую то скорее всего она неправильная и старая. Лет 10 назад действительно неграмотные авторы так учили делать, в итоге появилась куча уязвимого кода.
> techo $row['text'] . "<br />";
А это уже XSS, вот мой урок на тему: https://gist.github.com/anonymous/52adda0113428b274c64
А, и еще расширение mysql устарело. Используй mysqli или PDO: http://habrahabr.ru/post/137664/
Да, верно, там в документации есть готовый файл. А в статье на хабре можно прочесть и понять как это работает (работает просто: если идет обращение по URL который не соответствует никакму файлу, вызвать index.php)
>>441288
Исправь замечания, которые я написал выше. Пока у тебя не правильный ООП код, а просто функции случайно по классам разбросаны.
>>441320
Вот это как раз пример неправильно кода. зачем делать strip_tags при вставке в БД? БД никаких проблем от вставки html тегов не испытывает.
Явно его писал человек который в php не разбирается (и в узявимостях) и который просто все функции которые знал собрал вместе.
Ну и
> mysql_real_escape_string
Устарела
Кстати, strip_tags не защищает на 100% от XSS. Например если есть код
<?php
$value = strip_tags($_GET['value']);
?>
<input value="<?= $value ?>">
То тут возможна XSS если в $value вставить
" onfocus="скрипт" autofocus
>>441330
> Работает, но выводит он мне все записи, кроме той, которую я только что добавил.
Скорее всего она не добавилась из-за ошибки потому и не выводится. У тебя включен вывод ошибок? Если нет то очень плохо, как ты вслепую угадаешь в чем причина?
Также, код ужасен.
В коде у тебя SQL инъекция :
https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0
http://forum.antichat.ru/thread43966.html
Данные в запрос надо вставлять через плейсхолдеры:
http://habrahabr.ru/post/148701/
Если статья или учебник вставляет данные напрямую то скорее всего она неправильная и старая. Лет 10 назад действительно неграмотные авторы так учили делать, в итоге появилась куча уязвимого кода.
> techo $row['text'] . "<br />";
А это уже XSS, вот мой урок на тему: https://gist.github.com/anonymous/52adda0113428b274c64
А, и еще расширение mysql устарело. Используй mysqli или PDO: http://habrahabr.ru/post/137664/
Как включить вывод ошибок:
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Проверить, работает ли вывод ошибок, можно запустив скрипт содержающий обращение к несуществующей переменной вроде echo $sdgasdad; и проверив, выведется ошибка или нет. Если все верно, то должна вывестись.
>Скорее всего она не добавилась из-за ошибки потому и не выводится. У тебя включен вывод ошибок? Если нет то очень плохо, как ты вслепую угадаешь в чем причина?
Нет, она добавляется. То есть, если посмотреть через админку MySQL, то там все есть и если запустить форму по новой, то предыдущее значение теперь выйдет (а вновь введенное опять нет).
>Если вставилось успешно то должна сразу же выводиться.
Вот я поэтому тут и спрашиваю - должна, но нифига. Попробуй сам или подскажи другой код, где работает.
Я подозреваю, что проблема не в этом коде. Этот код же не сам по себе, у тебя какие-то другие файлы там еще есть, может быть из-за того как ты вызываешь этот код ты чего-то не видишь. Или ты что-то перепутал.
Этот код может либо не вставить запись вообще, либо вставить и вывести все что есть.
А, я туплю. Ошибка в твоем коде, смотри:
> $sql = "INSERT INTO table1(text) VALUES('$dan')";
> $zaprSQL = "SELECT * FROM table1";
> $rezs = mysql_query($zaprSQL);
запрос из переменной $sql вообще не выполняется. И ты ничего никуда не вставялешь.
Ну и код ужасен, я выше написал почему.
Есть изображение завернутое в ссылку.
У всех ссылок на изображение одно и тоже "name".
<a href = "" name ="" >
<img src = "">
</a>
Как можно вытащить "href" ссылки, которая оборачивает тег через <img>.
и сделал файлообменник на слиме, вот прошу его проверить.
Спасибо.
https://github.com/NotBadCode/Students
https://github.com/NotBadCode/Upload
Мне задачки ОПа проще на ассембли было написать, чем на php. Сразу начал свой фейс-бух хуячить, периодически в help заглядывая. Фейс-бух это такая социальная сеть для бух-галтеров.
>запрос из переменной $sql вообще не выполняется. И ты ничего никуда не вставялешь.
Да, теперь разобрался, тем не менее, у меня каким-то чудом все вставлялось.
>Ну и код ужасен, я выше написал почему.
Да, это буду учитывать в дальнейшем. Спасибо.
А нет, лол, он теперь вставляет два раза, поэтому и выводит. Блин, в чем там дело-то.
Разобрался. Оказывается, при проверке
if(!mysql_query($sql))\t{
\t\techo "<center><p><b>Ошибка при добавлении данных!</b></p></center>";
\t}
\telse\t{
\t\techo "<center><p><b>Данные добавлены!</b></p></center>";
\t}
Выполняется сам запрос mysql_query($sql).
public $variable;
public function someFunction() {
$this->variable = new First();
...
}
}
Это хороший тон для ООП?
По этому куску кода нельзя сказать. Может хороший, а может нет, зависит от того что надо сделать.
класс состоящий из классов это нормально
Т.е класс внутри класса, это ничего страшного?
Я хочу сделать твою задачку по ООП про компанию "Вектор".
Хочу сделать класс Cотрудник в котором будет указываться его //имя, должность. Ранг, зарплата, кофе, документы будут вычисляться методом при создании класса.
Далее, будет класс Департамент, который будет создавать Сотрудников и вычислять\выводить необходимые данные.
Спс те. Знач буду так делать.
Например, есть класс User.
Есть метод User::getFav (возвращает любимый предмет юзера).
Любимые предметы могут быть разные: "любимая еда", "любимая музыка", и т.д. И храниться они могут совсем в разных местах: базе данных типа SQL или в *.txt файлах.
Заранее мы не можем предсказать, что именно нам потребуется получить в будущем, любимую музыку или любимую еду пользователя, или ещё что-то, и из какого места хранения мы хотим это получить. В самом классе User описывать перечень возможных мест хранения и способов подключения к местам хранения, перебирать их через switch или if слишком суетно. Делать всё это зависимым от глобальных переменных ненадёжно, ведь глобальные переменные может изменить кто угодно где угодно и потом ищи-свищи.
Поэтому при создании объекта User::__construct($type) аргумент $type может являться объектом, указывающим тип места хранения, к которому мы подключимся для извлечения любимого предмета, и свойств такого подключения.
Объект класса User, в свою очередь, при создании заносит в своё свойство private $db_type переданнный аргумент $type, и дальше все методы, в том числе User::getFav работают через эту зависимость.
Таким образом мы сделали класс универсальным, мы можем передавать ему различные места хранения любимого предмета, тип любимого предмета, способы извлечения этого предмета из мест хранения, не оглядываясь на то какое именно место хранения и какой именно предмет нам понадобится.
Вот это внедрение $type в качестве аргумента User::_construct($type) с последующим сохранением в private свойстве и является тем самым внедрением зависимости.
Правильно ли я понимаю, и если нет, объясните пожалуйста на этих аналогиях принцип dependency injection.
Не очень правильно создавать сотрудников в Департаменте. Ведь они не в департаменте появляются, а их туда назначают.
Гораздо правильнее сделать там метод добавитьСотрудника(сотрудник)
>>441476
У меня есть урок про DI: https://gist.github.com/codedokode/e1d31a31b37d5f635057
DI это вообще другое. Это способ решения проблемы связей между классами, что делать если классу A для работы нужны классы B и С (DI отвечает: надо внедрять их через конструктор например).
Твой вопрос скорее вопрос про мапперы: как сохранять и загружать данные из внешних хранилищ. У меня и на эту тему есть урок: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
По твоему коду, ты пытаешься один класс сделать ответсвенным за все, и за хранение информаци о пользователе, и за получение ее. Нехорошо.
Лучше сделать для того 2 класса. Например пусть класс UserMapper загружает информацию о пользователе и вносит ее в класс User:
$user = $userMapper->loadById(100);
Маппером он называется так как отображает объект User на какое-то хранилище (то есть сохраняет туда и загружает).
Если используется несколько хранилищ (что странно), то можно сделать UserMapper чем-то вроде фасада который загружает информацию из UserDBRepository и UserFileRepository и собирает вместе.
> Поэтому при создании объекта User::__construct($type) аргумент $type может являться объектом, указывающим тип места хранения, к которому мы подключимся для извлечения любимого предмета, и свойств такого подключения.
Это вообще как-то неправильно. Ты предполагаешь что пользователь обязан где-то храниться, но почему? Я могу захотеть просто создать пользователя в памяти и никуда не сохранять.
И более того, чтобы загружать себя откуда-то пользователю надо как-то получить ссылки на объекты которые этим занимаются (наример на соединение с БД).
Нехорошо, лучше сделать чтобы User ничего не умел сам загружать и вообще не знал где хранится информация о нем. Пусть этим занимается другой класс-маппер.
Не очень правильно создавать сотрудников в Департаменте. Ведь они не в департаменте появляются, а их туда назначают.
Гораздо правильнее сделать там метод добавитьСотрудника(сотрудник)
>>441476
У меня есть урок про DI: https://gist.github.com/codedokode/e1d31a31b37d5f635057
DI это вообще другое. Это способ решения проблемы связей между классами, что делать если классу A для работы нужны классы B и С (DI отвечает: надо внедрять их через конструктор например).
Твой вопрос скорее вопрос про мапперы: как сохранять и загружать данные из внешних хранилищ. У меня и на эту тему есть урок: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
По твоему коду, ты пытаешься один класс сделать ответсвенным за все, и за хранение информаци о пользователе, и за получение ее. Нехорошо.
Лучше сделать для того 2 класса. Например пусть класс UserMapper загружает информацию о пользователе и вносит ее в класс User:
$user = $userMapper->loadById(100);
Маппером он называется так как отображает объект User на какое-то хранилище (то есть сохраняет туда и загружает).
Если используется несколько хранилищ (что странно), то можно сделать UserMapper чем-то вроде фасада который загружает информацию из UserDBRepository и UserFileRepository и собирает вместе.
> Поэтому при создании объекта User::__construct($type) аргумент $type может являться объектом, указывающим тип места хранения, к которому мы подключимся для извлечения любимого предмета, и свойств такого подключения.
Это вообще как-то неправильно. Ты предполагаешь что пользователь обязан где-то храниться, но почему? Я могу захотеть просто создать пользователя в памяти и никуда не сохранять.
И более того, чтобы загружать себя откуда-то пользователю надо как-то получить ссылки на объекты которые этим занимаются (наример на соединение с БД).
Нехорошо, лучше сделать чтобы User ничего не умел сам загружать и вообще не знал где хранится информация о нем. Пусть этим занимается другой класс-маппер.
Ты немного сумбурно расписал, но в общем ты всё правильно понял. Предположим у тебя есть класс, который выполняет какую-то свою задачу и у тебя появилась необходимость логировать информацию, допустим в тхт файл. Проще всего было бы прямо на месте в этом классе создать метод логирования и вызывать его где нужно. Но тогда бы ты нарушил принцип single responsibility, который гласит, что один объект должен выполнять только одно действие. Более того, ты бы нарушил принцип открытости/закрытости, ведь если бы понадобилось изменить способ логирования, скажем не в файлик, а в базу, то пришлось бы руками менять код основного класса, что неприемлемо.
Тогда можно было бы создать класс логирования отдельно class FileLogger, и создавать его экземпляр в конструкторе основного класса и засовывать в приватное поле private $loger и вызывать его по месту через $this->loger->log(); Но тогда бы ты нарушил принцип инверсии зависимостей и опять же принцип открытости/закрытости, так как при изменении способа логирования пришлось бы лазить в конструктор основного класса и менять там $this->loger = new FileLoger на $this->loger = new DbLogger. Теперь основной класс хоть и не диктует как именно логировать, он всё равно ответственен за выбор объекта, что неправильно.
Поэтому выход в следующем: создаём публичный метод-сеттер с сигнатурой
public function(ILoger $loger) который будет принимать любой логер имплементирующий интерфейс Iloger, не задумываясь о том, что именно это за логер. Это и есть ООП абстракция и программирование не на уровне реализаций, а на уровне интерфейсов. Теперь будучи в основном классе ты можешь рассматривать $loger, как некий абстрактный логер, который будет делать то, что нужно именно клиенту твоего кода, без изменений в нём. Ну и нужно будет создать интерфейс ILoger с обязательными сигнатурами и каждый класс FileLoger, DbLoger, SomeWhereElseLoger должны будут этот интерфейс заимплементить.
>метод-сеттер с сигнатурой
public function setLoger(ILoger $loger)
fix
Олсо, дополню сеья. Тут у тебя может возникнуть вопрос, так а нах нужен этот самый интерфейс? Нужен потому что если в интерфейсе объявлена сигнатура скажем public function log($info); то ты теперь можешь с полной уверенностью в своём главном классе использовать $this->loger->log($someData);
Да ты не знаешь, что именно за логер используется, но ты точно знаешь, что он умеет делать ->log($something), ведь у тебя в тайп хинте сеттера указано public function setLogger(ILoger $loger)
>>441018
https://github.com/tokotun/uppy
>А ты все файлы в одну папку кладешь? Что если загрузить 2 файла с одинаковым именем но разным содержимым?
Это я предусмотрел. Имя файла хранится в БД. А в сам файл хранится под уникальным кодом
ну как то так D:\localhost\uppy\uppy\container\GhKEGFeeqJ
А когда скачивается, то файл получает сохраненное имя из БД.
>Обычно эта ссылка ведет на главную. Непонятно почему она разная в разных шаблонах.
Потому что так сделано в RGhost.ru. Там кликом по лейблу можно переключатся между страничкой загрузки и страничкой закаченных файлов. Я же его копию делаю.
>В форме поиска надо добавить кнопку. Я не уверен что без кнопки она вообще будет отправляться.
Запрос отправляется нажатием на Enter. Опять же слизано с RGhost.ru там нет кнопки.
> header('Content-Disposition: attachment; filename=' . $this->name);
>для опции filename разрешено использовать только латиницу (ASCII если точнее). русские буквы разные браузеры понимают по-разному. Лучше не используй эту опцию вообще.
мм... Именно эта опция отвечала за переименование файла. Из ..\uppy\container\GhKEGFeeqJ в .\uppy\container\filename.jpg
Тогда, мне придётся поискать альтернативу.
Пока на примете 2 варианта. Или вовсе не менять имя файла на уникальный код. И тогда не смогу хранить файлы с одинаковыми именами.
Или сделать велосипедную свистопляску - перед скачиванием загружать под исходным именем этот файл в какую-то папку. А потом уже этот переименованный
файл отдавать на скачивание.
Ну, или какие существуют варианты этого решения?
>Я думаю, удобно при загрузке из БД преобразовать дату из mysql в php формат. А при вставке делать обратное.
Не уверен что правильно понял. Это нужно, для того, что б из такого формата "2011-06-10 15:18:00" переделывать в такой “4 июня 2011, 14:57″ ? Верно?
>Индекс по dateLoad сделал?
Теперь сделал.
>Ты отключил выполнение php скриптов в папке загрузок?
Нашел такое решение - создать в каталоге с файлами .htaccess
php_flag engine 0
AddType "text/html" .php .cgi .pl .fcgi .fpl .phtml .shtml .php2 .php3 .php4 .php5 .asp .jsp
но файлы у меня закачиваются без расширений. Нужен ли такой вариант?
>начинать загрузку и передавать ее Апачу с помощью X-Sendfile
Это у меня не работает. Я плох в английском. Сделал так как понял.
Скачал с гитхаба mod_xsendfile.so , тот, где Apache2.4 для Windows.
прописал в конфиге у апача
LoadModule xsendfile_module modules/mod_xsendfile.so
и перезагрузил
в .htaccess прописал
<Files index.php>
\tXSendFile on
</Files>
В итоге. При попытке скачать выдаёт 404.
>>441018
https://github.com/tokotun/uppy
>А ты все файлы в одну папку кладешь? Что если загрузить 2 файла с одинаковым именем но разным содержимым?
Это я предусмотрел. Имя файла хранится в БД. А в сам файл хранится под уникальным кодом
ну как то так D:\localhost\uppy\uppy\container\GhKEGFeeqJ
А когда скачивается, то файл получает сохраненное имя из БД.
>Обычно эта ссылка ведет на главную. Непонятно почему она разная в разных шаблонах.
Потому что так сделано в RGhost.ru. Там кликом по лейблу можно переключатся между страничкой загрузки и страничкой закаченных файлов. Я же его копию делаю.
>В форме поиска надо добавить кнопку. Я не уверен что без кнопки она вообще будет отправляться.
Запрос отправляется нажатием на Enter. Опять же слизано с RGhost.ru там нет кнопки.
> header('Content-Disposition: attachment; filename=' . $this->name);
>для опции filename разрешено использовать только латиницу (ASCII если точнее). русские буквы разные браузеры понимают по-разному. Лучше не используй эту опцию вообще.
мм... Именно эта опция отвечала за переименование файла. Из ..\uppy\container\GhKEGFeeqJ в .\uppy\container\filename.jpg
Тогда, мне придётся поискать альтернативу.
Пока на примете 2 варианта. Или вовсе не менять имя файла на уникальный код. И тогда не смогу хранить файлы с одинаковыми именами.
Или сделать велосипедную свистопляску - перед скачиванием загружать под исходным именем этот файл в какую-то папку. А потом уже этот переименованный
файл отдавать на скачивание.
Ну, или какие существуют варианты этого решения?
>Я думаю, удобно при загрузке из БД преобразовать дату из mysql в php формат. А при вставке делать обратное.
Не уверен что правильно понял. Это нужно, для того, что б из такого формата "2011-06-10 15:18:00" переделывать в такой “4 июня 2011, 14:57″ ? Верно?
>Индекс по dateLoad сделал?
Теперь сделал.
>Ты отключил выполнение php скриптов в папке загрузок?
Нашел такое решение - создать в каталоге с файлами .htaccess
php_flag engine 0
AddType "text/html" .php .cgi .pl .fcgi .fpl .phtml .shtml .php2 .php3 .php4 .php5 .asp .jsp
но файлы у меня закачиваются без расширений. Нужен ли такой вариант?
>начинать загрузку и передавать ее Апачу с помощью X-Sendfile
Это у меня не работает. Я плох в английском. Сделал так как понял.
Скачал с гитхаба mod_xsendfile.so , тот, где Apache2.4 для Windows.
прописал в конфиге у апача
LoadModule xsendfile_module modules/mod_xsendfile.so
и перезагрузил
в .htaccess прописал
<Files index.php>
\tXSendFile on
</Files>
В итоге. При попытке скачать выдаёт 404.
http://explainshell.com/explain?cmd=rsync+-chavzP+--stats+user%40remote.host%3A%2Fpath%2Fto%2Fcopy+%2Fpath%2Fto%2Flocal%2Fstorage
Правда, на английском.
Шindoшs переустанавливать уже пробовал? Попробуй переустановить ещё раз.
Или воспользуйся нормальным редактором и сохрани код в кодировке UTF-8.
Мимоизвращенец не пишущий классов
хз, я его не знаю, но мне кажется что нужен. Я вот пока что пишу небольшой форум на процедурке, и мне уже начинает казаться, что если я буду накручивать на него функционал, то все там захлебнется в количестве костылей и говнокода. Утонет во всяких if и прочих include. Про ооп знаю только то, что мол помогает реализовать всё как в жизни и раскидать всё по полочкам, тот класс за то отвечает, тот за то. Думаю что оно нужно и пригодится мне в итоге.
Не, я вообще 6 глав за день сделал, благо свободного времени более чем дохуя. Но все равно спасибо.
Нет, только второй день учу, сейчас на седьмой главе.
Первый: http://ideone.com/gwfRo7
От второго у меня вообще KANSAS SITY SHUFFLE : http://ideone.com/NU8v7y
>У тебя первый язык с которым ты познакомился был Явой?
В общем-то да, не считая попыток осилить кресты
Например
Можно не прописывать самому каждому массиву свой рандом. А определять количество элементов в массиве с помощью count
https://php.net/manual/ru/function.count.php
Там нужно написать все орфогрфические ошибки в одном регулярном выражении или для каждого свое?
приведите пример кода пожалуйста
чтобы не лезть туда
Нужно написать скрипт проверяющий текст на наличие орфографических ошибок.
Сначала он сплитится на массив?
не нужно. Да и как ты определишь вот это
нет пробела после запятой, точки с запятой, восклицательного знака, вопросительного знака, двоеточия
если разобьёшь на массив.
Если не прописывать рандом для каждого отдельного слова, или не обновлять его как-нибудь каждый раз перед новым словом, то первая и вторая строчка стишка в output будут одинаковые, поскольку их структура
word1 word2 word3
word1 word2 word3
word4 word5
и стих будет уровня
Внезапных слов сухие листья
Внезапных слов сухие листья
Я оставляю смысл жизни
да и
Как ты запишешь count в рандом?
$letters = array('а','б','в','г','д');
$number = count($letters);
$random = mt_rand(0, $number);
Если так - ничего не выйдет. Count считает количество элементов(в данном случае их 5), а в массиве элементы дефолтно нумеруются с нуля. Следовательно, 0-4. Если выпадает пятерка - fail, ничего на экран не выведется.
Это можно легко проверить на http://ideone.com/MYx54x
Что бы задать поиск нескольких вариантов слова, применяется символ "|" (вертикальная черта)
или //S здесь соотвертствует любому символу кроме пробела.
Вот регулярка где после любого из этих символов . , ; ! ? : стоит непробел
точка и запятая тут экранируются
/\.\S|,\S|;\S|!\S|\?\S|:\S/u
можно её чуть покороче записать
/(\.|,|!|:|\?|!)\S/u
А потом добавлять через | остальные правила. Вот на жи, ши, например.
/(\.|,|!|:|\?|!)\S|жы|шы/u
Слишком, но работает же.
Зачем вообще сортировать все массивы по стопитсот раз, что б затем вывести случайный его элемент?
Просто я перфекционист, мне недостаточно РАБОТАЕТ НУ И ХУЙ С НИМ[/ b] . Постоянное желание допилить напильником все до конца, шоб блестело.
ПРОЁБ РАЗМЕТКИ! ВОТ ЭТО БОЛЬ ПЕРФЕКЦИОНИСТА
Ты бы подробности написал, в какой программе ошибка, при выполнении какого действия.
>>441584
Нужен.
>>441631
Можно несколько регулярок.
>>441637
Можно до или после проверять или вообще не разбивать на массив.
>>441622
> $random1 = mt_rand(0,3);
то неудобно так как надо вручную считать число слов и пересчитывать при изменении массива. Надо сделать либо через count либо через функцию array_rand которая возвращает случайно выбранный ключ массива.
И ошибки исправить, они внизу написаны:
> PHP Notice: Undefined variable: rando5 in /home/iAXCy2/prog.php on line 34
> От второго у меня вообще KANSAS SITY SHUFFLE :
Не, это наверно уже усложнение, массив сортировать незачем.
Ты бы подробности написал, в какой программе ошибка, при выполнении какого действия.
>>441584
Нужен.
>>441631
Можно несколько регулярок.
>>441637
Можно до или после проверять или вообще не разбивать на массив.
>>441622
> $random1 = mt_rand(0,3);
то неудобно так как надо вручную считать число слов и пересчитывать при изменении массива. Надо сделать либо через count либо через функцию array_rand которая возвращает случайно выбранный ключ массива.
И ошибки исправить, они внизу написаны:
> PHP Notice: Undefined variable: rando5 in /home/iAXCy2/prog.php on line 34
> От второго у меня вообще KANSAS SITY SHUFFLE :
Не, это наверно уже усложнение, массив сортировать незачем.
Не, это не очень хорошая идея, сортировать массив ради выборки элемента когда есть mt_rand и array_rand.
В PHP тоже есть DOM: http://php.net/manual/ru/class.domdocument.php
А вообще, твоя задача решается с DOM и XPAth. Xpath это язык запросов для поиска узлоов в доме. С ним можно например искать все теги a внутри которых есть img.
http://ideone.com/VDERi0
перепиливаю свою гостевуху под подготовленные запросы и ООП-стиль mysqli_ вместо процедурного. И вот вопрос, в этом коде нужен подготовленный запрос? Я как бы понимаю, что он нужен там, где я подставляю в запрос переменную, а тут?
После обращения к методам вроде $mysqli->prepare( надо делать проверку не произошла ли ошибка.
http://ideone.com/6ArA06
Вот так хорошо? Не после каждой же строчки работы с базой писать проверку на ошибки? Если execute() сработал, значит дальше уже будет всё хорошо?
Спасибо!
\tfunction Grammar ($text) {
\t\t$regexp = '/(\.|,|:|!|?|)\S|жы|шы/u';
\t\tif (preg_match($regexp , $text)){
\t\t\techo "Внимание, обнаружена ошибка!";
\t\t}
\t\telse {
\t\t\techo "Ошибок не обнаружено.";
\t\t}
\t
\t}
\tGrammar ('жы шы пиши с буквой и');
Не подскажешь, почему условие всегда говорит что ошибок нет?
В файл логов выдается ошибка
Compilation failed: nothing to repeat at offset 10
Для регулярок. Есть сайты наподобие ideon. Там удобно экспериментрировать. И сразу видно что они находят.
Скинул бы их названия да вакаба не пропускает.
Ошибка. Строчка же закомментирована и ошибка в ней никак не ловится php.
>>441700
Только лучше пиши имена функций с маленькой буквы. с большой принято писать имена классов и константы.
>>441693
Это надо читать в php мануале по конкретной функции, может она вернуть ошибку или нет. Я наизучть не помню.
Также, наверняка есть какая-то готовая библиотека которая сама проверяет результат и при ошибке например выкидывает исключение.
Ну да, не ловится. Если эту строчку не раскомментировать и не заюзать для проверки скрипта. Спасибо за ответ.
Зачем перекатился?
Нет, я как истинный гуманитарий заменил одиночные кавычки на двойные. Блджад, мне еще практиковаться и практиковаться. Порой глупейшие ошибки совершаю. Вот сейчас засел за задачку с числами прописью, чувствую, я далеко не раз выматерюсь на себя за свою тупость, пока её решаю.
>базовая ставка
Я что-то не могу найти этого в задаче. Или это то, сколько получает простой сотрудник 1го ранга? Тогда почему в абстрактный класс нельзя запихнуть кофе и бумаги?
Но ты же сказал что
> у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом
но также есть и кофе и бумаги. Тогда почему нельзя все положить в один абстрактный класс?
С помощью js лови выбор первого селекта, шли аякс, получай в ответе данные для второго селекта, основанные на выборе первого. Тебе понадобятся событие onchange и http://jquery.page2page.ru/index.php5/Ajax-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81
Я привел не все свойства, а только часть для примера. Предполагается что остальные ты добавишь сам и поменяшь если тебе что-то не нравится.
> у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
Я имел в виду, ты хранишь в сотруднике только его ставку, а зарплату с учетом ранга и босса хранить не надо, а можно вычислить методом. Аналогично с кофе: ты хранишь только базовую велеичну, а общее потребление с учетом ранга и босса вычисляешь методом.
Я бы сначала в офис устроился, что бы опыта поднабраться, а потом уже думал, лезть ли туда или нет.
Наверное потому что там как таковых страничек и нету. Это не ссылка на страничку, а какой-то хитрый путь/запрос в базу. А страничка генерируется и верстается автоматически, просто беря инфу из базы. Сам уже задумывался над этим, но ответ не искал, поэтому ждем кто что еще скажет. Думаю что найду ответ изучая фреймворки.
Ну, я тоже так думаю, поэтому и спросил.
Напомни пожалуйста, как называется схема, когда в бд есть произвольное множество объектов, которые имеют произвольное количество свойств каждый? Чтобы св-ва и знач-ия в отдельной бд?
> public function getHit($k) //
Здесь ты неудачно выбрал параметр функции. Почему число? У нас же ООП. Передавай сразу объекты, кто и кого бьет:
getDamage(Hero $attacker, Hero $target)
Смотри, какая хорошая и понятная функция получилась
Не совсем понял, разве можно так давать ссылки на экземпляр объекта указывая его класс и через пробел сам экземпляр?
Сейчас зашел, а там сперва дух 90-х, потом хтмл5. Но что можно с этим сделать на практике в 2015?
Одно. Вот это
>Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
Опять же все зависит от конторы куда ты поступаешь. Был тут один, который устроился зная лишь самые основы.
я не ОП
Добра тебе.
Хм, вот смотри, там дается пример типа
>/articles.php?tag=summer&action=list — просмотр списка статей с меткой summer (лето).
У меня есть простенькая форма, в которой через кнопку выполняется скрипт, передается пара переменных (errorName и errorText). Если я создам гиперссылку, как в этом примере
>/action.php?errorName=err1&errorText=errt1
то нифига эти значения переменных не передадутся. Там надо еще что-то делать?
Тестирую все это на денвере.
Сформулирую по-человечески - что мне надо читать, чтобы научиться делать эти самые ЧПУ при создании сайта на апаче безо всяких CMS?
>кто хоть раз использовал ООП
А задаются эти вопросы теми, кто его не использовал и только начинают учить. И кто желают знать с какой целью они его учат, для мотивации. Если есть мотивация, то осваивается легче и быстрее же.
ООП и МВЦ, читай и используй ООП/МВЦ. Я реализовывал ЧПУ через создание экшенов, отлавливал введенный урл, создавал на лету имя экшена и вызывал его. Не очень сложно на практике.
Через штакцес не круто.
>Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Что-то нифига он не работает. Алсо, есть плагин для Notepad++ для подобного?
http://rutracker.org/forum/viewtopic.php?t=4620353
Что скажете по их поводу, по ним можно учиться?
http://htmlbook.ru/html/button/disabled
Перая же ссылка в гугле на запрос "Неактивная кнопка"
Средствами php внутири кнопки написать <button <?php echo 'disabled'; ?> >...</button>
>пока не выбран один из radio button
Пропустил эту строчку. Я жопой похоже читал.
PHP, исполняется на сервере. После того как он отдал страничку, больше он в неё не лезет.
Сделать эту кнопку неактивной на уже отправленной страничке ПХП не может.
$mysqli = new mysqli('localhost', 'root', 'pas', 'db');
Что делать если я например пробую писать что то в ООП стиле, допустим это будет гостевая книга, я сoздаю класс:
class User {
public $name;
public $email;
public $message;
}
Каким образом мне использовать перменную $mysqli? Её можно спокойно использовать внутри методов класса User?
Передаёшь функции переменную и можешь использовать её внутри этой функции.
f($mysqli);
Но, лучше класс User исползовать для работы с пользователем, а для работы с БД создать класс который и будет этим заниматься. И который будет иметь свойство $mysqli.
Но лучше используй PDO. Как то так.
Поставь себе phpStorm, там есть форматирование кода и вообще очень удобная и простая штука, когда начнешь писать что-то посложнее оценишь.
1. Качай евалюэйшен.
2. Качай файл с паролями с русракера
....
3. ПРОФИТ!
Типа того. Только там чекбокс, а мне надо на каждую радикнопку проверку сделать, если я правильно понимаю?
>Каким образом мне использовать перменную $mysqli? Её можно спокойно использовать внутри методов класса User?
Можно, если ты ее передашь непосредственно в метод. Но лучше, раз уж ты познаешь ООП, используй паттерны. Почитай статью ОПа, там довольно доступно написано https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a.
И да, используй PDO вместо mysqli.
<form method="get" action="">
\t<input type="radio" name="checkbox" onmousedown="this.form.submit.disabled=this.checked"><br>
\t<input type="radio" name="checkbox" onmousedown="this.form.submit.disabled=this.checked"><br>
\t<input type="submit" name="submit" value="Button" disabled><br>
</form>
Ага, спасибо.
abstract class Employee {
abstract public $rang;
abstract public $solary;
abstract public $leader;
public function __construct($rang = 1, $leader = false) {
$this->rang = $rang;
$this->leader = $leader;
self::clculateSolary();
}
public function calculateSolary() {
switch ($this->rang) {
case 2:
$this->solary = $this->solary + ($this->solary 0.25);
break;
case 3:
$this->solary = $this->solary + ($this->solary 0.50);
break;
}
if ($leader) {
$this->solary = $this->solary + ($this->solary * 0.50);
}
return $this->solary;
}
}
class Engineer extends Employee {
public $solary = 500;
}
$engineer = new Engineer(2);
...
abstract class Employee {
abstract public $rang;
abstract public $solary;
abstract public $leader;
public function __construct($rang = 1, $leader = false) {
$this->rang = $rang;
$this->leader = $leader;
self::clculateSolary();
}
public function calculateSolary() {
switch ($this->rang) {
case 2:
$this->solary = $this->solary + ($this->solary 0.25);
break;
case 3:
$this->solary = $this->solary + ($this->solary 0.50);
break;
}
if ($leader) {
$this->solary = $this->solary + ($this->solary * 0.50);
}
return $this->solary;
}
}
class Engineer extends Employee {
public $solary = 500;
}
$engineer = new Engineer(2);
...
не хочу с ними на винде дрочиться
https://github.com/NotBadCode/Upload
У тебя файлообменник работать должен?
А то что ошибки сплош и рядом лезут, что переменная не определена.
Не делай так, инлайн до добра не доводит. Юзай жикверя, отслеживай событие, вешай действие.
У тебя тут не передаётся переменная $file.
https://github.com/NotBadCode/Upload/blob/master/index.php#L27
И потому тут всплывает ошибка - переменная не определена.
https://github.com/NotBadCode/Upload/blob/master/templates/upload.html#L12
При попытке что, то закачать.
Опять же переменная $newcode не определена.
https://github.com/NotBadCode/Upload/blob/master/lib/file.php#L33
элемент массива $data['uploadtime'] не определен.
https://github.com/NotBadCode/Upload/blob/master/lib/file.php#L24
который должен определятся где то тут.
https://github.com/NotBadCode/Upload/blob/master/index.php#L42
Ну и так далее. Ты наверно на гитхаб не залил последние правки. Раз у тебя работает.
Предполагаю, что всю эту муть надо как-то в циклы засунуть, но как это сделать, межушный ганглий соображать отказывается.
Ты можешь настроить веб-сервер чтобы любой URL соответствовал любому файлу. То есть нанример при обращении /news/1/2/3 вызывался news.php. Или при обращении к 1.html вызывался 2.php
Обычно при исплоьзовании фреймворков все запросы перенаправляют на index.php, а там роутер анализирует URL и вызывает нужную функцию (кстати если будешь делать нашу задачку на файлообменник, познакомишься с этим способом).
>>442078
ООП был придуман для больбы со сложностью приложений. По мере роста объема кода обычное процедурное приложение прверащается в лапшу из функций и переменных (примеры: вордпресс, друпал). Его трудно поддерживать и трудно понять как оно работает.
ООП позволяет писать более аккуратный, структурированный (то есть разбитый на части), повторно используеый код. Это делается за счет того, что данные и функции для их обработки помещаются в отдельные классы, независимые друг от друга. каждый класс занимается своим делом, и чтобы что-то поправить, не надо разгребать весь код, достаточно поменять один класс.
Сам ООП начали исплоьзовать в 80-х годах прошлого века и постепенно этот подход вытеснил остальные в промышленной разработке.
Ну а привыкнув к ООП начинаешь его везде исплоьзовать, даже в простых приложениях.
Мы в нашем треде изучаем современные технологии и потому изуаем и используем ООП.
Entity Attribute value = EAV?
>>442112
> Не совсем понял, разве можно так давать ссылки на экземпляр объекта указывая его класс и через пробел сам экземпляр?
Hero это тайп хинт. Он говорит что в функцию можно передать только объект класса Hero или наследника.
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Все зависит от компании. Куда-то возьмут с первой, куда-то потребуют минимум 3 решить.
Полезнее кстати идти туда где требования выше, там ты большему научишься.
>>442137
HTML5 это расширение HTML4, а не другая технология. Также как CSS3 это дополнения к CSS2.
Основам они тебя научат. Ну а чтобы закрепить знания и проверить себя, реши наши задачки из «Пути HTML» которые есть в ОП-посте.
>>442151
> public function __destruct
А зачем? В 99% в PHP десктруктор не нужен.
> isAlive()
> return 0;
Для обозначения да/нет принято использовать true/false: http://php.net/manual/ru/language.types.boolean.php
> public function __construct($hero1, $hero2)
> $this->cloned[] = clone $hero1;
Это неправильно. Смотри, ты в конструкторе Game (то есть один раз за программу) делаешь 2 копии. А надо по-другому. Надо хранить исходных героев, а клоны делать перед битвой:
функция провести одну битву() {
сделать клон героев
сделать N раундов этими клонами
}
При этом хранить в свойствах клонов не надо. Ты хранишь в свойствах только то что должно храниться долгое время, а клоны нам нужны на один раз — провести одну битву и выкинуть их.
То что ты сейчас делаешь, выглядит как костыль — сохранить здоровье, а потом восстановить. Ведь по если мы начнем усложнять код, добавим допустим запас маны, очки опыта и тд то ты замучаешься их все восстанавливать в начальное состояние. Надо клонировать героев перед битвой (ну или надо сделать метод в герое для полного восстановления в начальное состояние, но по моему клонировать проще).
Хороший ООП код должен быть написан так, что если ты меняешь класс героя (например добавляешь новые характеристики), то тебе не надо править класс Game для их восстановления. В этом и суть ООП что достаточно поменять один класс и не надо лазить по всему коду.
> public function getHit($attacker, $target)
Поставь здесь и во всех остальных функциях куда передаются объекты или массивы, тайп хинты.
> $avoidAttackStat = $target->skill + $target->agility;
> $avoidCrit = $target->dodgeCrit;
Функция getHit($attacker, $target) поулчилась довольно сложной и запутанной. Я бы советовал вынести из нее отдельные расчеты в отдельные функции с понятными названиями:
- функция расчета $crit, полуает на вход 2 героев и возвращает $crit
- функция расчета $dodge
- функция расчета $block
Эти функции наверно должны принимать на вход обоих героев.
Так у тебя код станет проще и читабельнее, если его разбить на несколько функций. А сейчас ты смешал несколько расчетов в одну кучу и разобраться гораздо сложнее.
> return $target->isAlive( );
думаю в этом нет необходимости. Тот кто вызывает функцию getHit может сам вызвать isAlive. А так ты в функцию помещаешь лишний код.
Более того, функция названа неправильно. Ее можно назвать getHit если она только расситывает урон но не наносит его. А твоя функция должна назваться просто attack, hit, makeDamage или как-то так, чтобы название отражало то, что она делает.
Переменные надо переименовать:
$x -> $firstHeroHitCount или $firstHeroDobleHit или как-то так
> foreach ($this->heroes as $number => $hero) {
> if ($number == 0) {
Вообще-то можно просто написать
$first = $this->heroes[0];
Зачем цикл?
И сразу же второй вопрос, а зачем тебе вообще массив героев, не проще сразу сделать свйоства firstHero и secondHero?
Цифры 1, 2, 3 лучше заменить на константы Game::FIRST_HERO_WINS, SECOND_HERO_WINS, NOBODY_WINS. Это сделаеn код читабельнее, а сейчас то значит цифра непонятно.
Все зависит от компании. Куда-то возьмут с первой, куда-то потребуют минимум 3 решить.
Полезнее кстати идти туда где требования выше, там ты большему научишься.
>>442137
HTML5 это расширение HTML4, а не другая технология. Также как CSS3 это дополнения к CSS2.
Основам они тебя научат. Ну а чтобы закрепить знания и проверить себя, реши наши задачки из «Пути HTML» которые есть в ОП-посте.
>>442151
> public function __destruct
А зачем? В 99% в PHP десктруктор не нужен.
> isAlive()
> return 0;
Для обозначения да/нет принято использовать true/false: http://php.net/manual/ru/language.types.boolean.php
> public function __construct($hero1, $hero2)
> $this->cloned[] = clone $hero1;
Это неправильно. Смотри, ты в конструкторе Game (то есть один раз за программу) делаешь 2 копии. А надо по-другому. Надо хранить исходных героев, а клоны делать перед битвой:
функция провести одну битву() {
сделать клон героев
сделать N раундов этими клонами
}
При этом хранить в свойствах клонов не надо. Ты хранишь в свойствах только то что должно храниться долгое время, а клоны нам нужны на один раз — провести одну битву и выкинуть их.
То что ты сейчас делаешь, выглядит как костыль — сохранить здоровье, а потом восстановить. Ведь по если мы начнем усложнять код, добавим допустим запас маны, очки опыта и тд то ты замучаешься их все восстанавливать в начальное состояние. Надо клонировать героев перед битвой (ну или надо сделать метод в герое для полного восстановления в начальное состояние, но по моему клонировать проще).
Хороший ООП код должен быть написан так, что если ты меняешь класс героя (например добавляешь новые характеристики), то тебе не надо править класс Game для их восстановления. В этом и суть ООП что достаточно поменять один класс и не надо лазить по всему коду.
> public function getHit($attacker, $target)
Поставь здесь и во всех остальных функциях куда передаются объекты или массивы, тайп хинты.
> $avoidAttackStat = $target->skill + $target->agility;
> $avoidCrit = $target->dodgeCrit;
Функция getHit($attacker, $target) поулчилась довольно сложной и запутанной. Я бы советовал вынести из нее отдельные расчеты в отдельные функции с понятными названиями:
- функция расчета $crit, полуает на вход 2 героев и возвращает $crit
- функция расчета $dodge
- функция расчета $block
Эти функции наверно должны принимать на вход обоих героев.
Так у тебя код станет проще и читабельнее, если его разбить на несколько функций. А сейчас ты смешал несколько расчетов в одну кучу и разобраться гораздо сложнее.
> return $target->isAlive( );
думаю в этом нет необходимости. Тот кто вызывает функцию getHit может сам вызвать isAlive. А так ты в функцию помещаешь лишний код.
Более того, функция названа неправильно. Ее можно назвать getHit если она только расситывает урон но не наносит его. А твоя функция должна назваться просто attack, hit, makeDamage или как-то так, чтобы название отражало то, что она делает.
Переменные надо переименовать:
$x -> $firstHeroHitCount или $firstHeroDobleHit или как-то так
> foreach ($this->heroes as $number => $hero) {
> if ($number == 0) {
Вообще-то можно просто написать
$first = $this->heroes[0];
Зачем цикл?
И сразу же второй вопрос, а зачем тебе вообще массив героев, не проще сразу сделать свйоства firstHero и secondHero?
Цифры 1, 2, 3 лучше заменить на константы Game::FIRST_HERO_WINS, SECOND_HERO_WINS, NOBODY_WINS. Это сделаеn код читабельнее, а сейчас то значит цифра непонятно.
Покажи код. Непонятно что ты делаешь и что не рабоатет.
>>442205
А ты попробуй без ООП решить задачу про ООО вектор например (один анон сдался, другой написал какой-то адский лапшекод и сам наверно понял что ерунда получилась).
>>442224
mysqli (не mysql) тоже не старый. Но мне он например не нравится темто не умеет выбрасывать исключения и надо после каждой функции через if проверять ошибки.
>>442244
ява != яваскрипт
На PHP никак.
>>442251
А ты <?php в начале не забыл? Покажи код который не выравнвиается.
>>442280
я его не проходил. Мне не нравится что ООП там задвинули в 3-ю часть так как ООП нужен. Но ты можешь попробовать этот курс, почему бы и нет.
Но советую также решать наши задачки. У нас есть задачи и на HTML/CSS и на SQL, и на JS и они могут выявить если у тебя где-то есть пробелы в знаниях.
>>442314
Чтобы загружать/сохранять объекты из базы обычно пишут отдельный класс (UserMapper), а объект mysqli ты передаешь в конструктор этого класса.
Урок про работу с БД: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
Урок про DI (он сложный но может хоть немного поймешь): https://gist.github.com/codedokode/e1d31a31b37d5f635057
>>442337
Когда ставишь ссылку оставляй 1 пробел после нее, а то точка в нее добавляется.
>>442345
Неправильно использовать mousedown (ведь оно соответствует и нажатию правой и нажатию средней кнопок мыши). Есть событие change. Ты явно плохо знаешь события.
>>442370
Нет. Абстрактным может быть класс (это значит что нельзя создать объект такого класса) либо метод (это метод без тела, который обязаны реализовать наследники класса).
PHP тебе пишет на ideone:
> Properties cannot be declared abstract
> self::clculateSolary( );
self:: используется для вызова статических методов: http://php.net/manual/ru/language.oop5.static.php (это методы которым не нужен объект и которые вызываются на классе, а не на объекте).
> $this->solary = $this->solary + ($this->solary
это тоже плохая идея. Лучше в salary хранить базовую ставку, а зарплату никуда не сохранять, а просто сделать метод который рассчитает и вернет ее. А то что делать если мы решили повысить работника с 1 до 2 ранга? В моем варианте достаточно поменять rang c 1 на 2 и все будет работать правильно. А в твоем?
Покажи код. Непонятно что ты делаешь и что не рабоатет.
>>442205
А ты попробуй без ООП решить задачу про ООО вектор например (один анон сдался, другой написал какой-то адский лапшекод и сам наверно понял что ерунда получилась).
>>442224
mysqli (не mysql) тоже не старый. Но мне он например не нравится темто не умеет выбрасывать исключения и надо после каждой функции через if проверять ошибки.
>>442244
ява != яваскрипт
На PHP никак.
>>442251
А ты <?php в начале не забыл? Покажи код который не выравнвиается.
>>442280
я его не проходил. Мне не нравится что ООП там задвинули в 3-ю часть так как ООП нужен. Но ты можешь попробовать этот курс, почему бы и нет.
Но советую также решать наши задачки. У нас есть задачи и на HTML/CSS и на SQL, и на JS и они могут выявить если у тебя где-то есть пробелы в знаниях.
>>442314
Чтобы загружать/сохранять объекты из базы обычно пишут отдельный класс (UserMapper), а объект mysqli ты передаешь в конструктор этого класса.
Урок про работу с БД: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
Урок про DI (он сложный но может хоть немного поймешь): https://gist.github.com/codedokode/e1d31a31b37d5f635057
>>442337
Когда ставишь ссылку оставляй 1 пробел после нее, а то точка в нее добавляется.
>>442345
Неправильно использовать mousedown (ведь оно соответствует и нажатию правой и нажатию средней кнопок мыши). Есть событие change. Ты явно плохо знаешь события.
>>442370
Нет. Абстрактным может быть класс (это значит что нельзя создать объект такого класса) либо метод (это метод без тела, который обязаны реализовать наследники класса).
PHP тебе пишет на ideone:
> Properties cannot be declared abstract
> self::clculateSolary( );
self:: используется для вызова статических методов: http://php.net/manual/ru/language.oop5.static.php (это методы которым не нужен объект и которые вызываются на классе, а не на объекте).
> $this->solary = $this->solary + ($this->solary
это тоже плохая идея. Лучше в salary хранить базовую ставку, а зарплату никуда не сохранять, а просто сделать метод который рассчитает и вернет ее. А то что делать если мы решили повысить работника с 1 до 2 ранга? В моем варианте достаточно поменять rang c 1 на 2 и все будет работать правильно. А в твоем?
А у тебя включен вывод ошибок?
В PHP по умолчанию выключено отображение ошибок в браузере, так как обычному пользователю сайта эта информация ни к чему. Но тебе, как программисту, надо видеть эти ошибки. Вот, как можно их просмотреть:
- ошибки сохраняются в лог ошибок. Можно открыть его и почитать. Если ты запускаешь код на локалхосте, у себя, то лог хранится в папке Апача (обычно она называется logs) и имеет название вроде error.log (в линуксе в папку /var/log/apache2 ). Если на хостинге — там либо есть файл error.log либо раздел в панели управления, где лог можно посмотреть
- также, ты можешь включить отображение ошибок. Открой файл php.ini, поставь там display_errors = On и error_reporting = E_ALL и перезапусти сервер. Теперь ошибки должны выводиться на экран.
Проверить, работает ли вывод ошибок, можно запустив скрипт содержающий обращение к несуществующей переменной вроде echo $sdgasdad; и проверив, выведется ошибка или нет. Если все верно, то должна вывестись.
на винде можно исплоьзовать метод с htaccess. Настроить его так чтобы при запросе
/download/abcdef/filename.txt
отдавался бы файл /container/abcdef (который браузер сохранит как filename.txt из-за того что в URL стоит это имя).
Попробуй, это не сверхсложно, на хабре есть статья про mod_rewrite.
Ошибки, которые нашел другой анон, надо бы исправить.
Насчет композера, ты зря его избегаешь. Он прекрасно работает под виндоуз. Если ты не доверяешь его инсталлятору, ты можешь скачать с оф. сайта composer.phar и запускать командой
php c:\files\composer.phar install
То есть указывая полный путь. Перед тем как выполнять команду, надо перейти в папку проекта разумеется. Если composer.phar лежит в папке проекта то писать путь не надо.
Если у тебя php не в PATH то и к php надо писать полный путь:
c:\php\php.exe c:\files\composer.phar install
Вот мой гайд по командной строке: https://gist.github.com/codedokode/10539568
Просто ты уже не совсем начинающий, потому с тебя спрос выше, и хорошо бы уметь пользоваться командной строкой хотя бы на уровне «выполнить простую команду».
Если что-то тебе кажется непонятным, задавай вопросы. Там где-то была на хабре статья про композер, ты ее сам можешь найти и почитать.
Фактически от тебя требуется создать composer.json, прописать туда нужные библиоетки (Slim) и их версии, и запустить установку через композер. А потом в index.php подключиь файл vendor/autoload.php.
Поэкспериментировать с композером лучше не на проекте, а на пустой папке (ее можно всегда удалить и создать заново). Создай папку, положи туда composer.phar, создай composer.json, запусти композер из консоли и попробуй установить что-нибудь. Композер должен создать папку vendor и в нее установить указанную тобой библиотеку.
Поначалу конечно что-то может не заработать. Пиши тогда в тред. думаю, лучше сразу разобарться с проблемой.
А и еще. Это же твоя вторая задача, было бы хорошо для шаблонизатора исплоьзовать twig. Ведь простые php-шаблоны ты уже исплоьзовать в первой задаче, лучше изучить новую библиотеку. Тем более что он удобнее чем простые php-шаблоны.
на винде можно исплоьзовать метод с htaccess. Настроить его так чтобы при запросе
/download/abcdef/filename.txt
отдавался бы файл /container/abcdef (который браузер сохранит как filename.txt из-за того что в URL стоит это имя).
Попробуй, это не сверхсложно, на хабре есть статья про mod_rewrite.
Ошибки, которые нашел другой анон, надо бы исправить.
Насчет композера, ты зря его избегаешь. Он прекрасно работает под виндоуз. Если ты не доверяешь его инсталлятору, ты можешь скачать с оф. сайта composer.phar и запускать командой
php c:\files\composer.phar install
То есть указывая полный путь. Перед тем как выполнять команду, надо перейти в папку проекта разумеется. Если composer.phar лежит в папке проекта то писать путь не надо.
Если у тебя php не в PATH то и к php надо писать полный путь:
c:\php\php.exe c:\files\composer.phar install
Вот мой гайд по командной строке: https://gist.github.com/codedokode/10539568
Просто ты уже не совсем начинающий, потому с тебя спрос выше, и хорошо бы уметь пользоваться командной строкой хотя бы на уровне «выполнить простую команду».
Если что-то тебе кажется непонятным, задавай вопросы. Там где-то была на хабре статья про композер, ты ее сам можешь найти и почитать.
Фактически от тебя требуется создать composer.json, прописать туда нужные библиоетки (Slim) и их версии, и запустить установку через композер. А потом в index.php подключиь файл vendor/autoload.php.
Поэкспериментировать с композером лучше не на проекте, а на пустой папке (ее можно всегда удалить и создать заново). Создай папку, положи туда composer.phar, создай composer.json, запусти композер из консоли и попробуй установить что-нибудь. Композер должен создать папку vendor и в нее установить указанную тобой библиотеку.
Поначалу конечно что-то может не заработать. Пиши тогда в тред. думаю, лучше сразу разобарться с проблемой.
А и еще. Это же твоя вторая задача, было бы хорошо для шаблонизатора исплоьзовать twig. Ведь простые php-шаблоны ты уже исплоьзовать в первой задаче, лучше изучить новую библиотеку. Тем более что он удобнее чем простые php-шаблоны.
Про коду.
> singleton('newDM'
Лучше назвать нормально, filesMapper. Ведь это маппер для файлов? Ну так и называй его fileMapper.
Класс тоже стоит переименовать. Заодно научишься пользоваться функцей «найти и заменить во всех файлах». В Sublime это например Ctrl + Shift + H.
> require_once "/lib/Datamapper.php";
В php есть такая штука как автозагрузка. Это когда при обращению к несущестующему классу вызывается функция-автозагрузчик и она может приинклудить нужный файл с классом. Таким образом, require писать не требуется.
Теория: http://php.net/manual/ru/language.oop5.autoload.php
При исплоьзовании композера тебе вообще не надо писать автозагрузчик так как в композере он уже есть. Тебе надо лишь в composer.json написать в какой папке искать файлы (и сами файлы должны быть названы также как и класс). Вот доки на английском: https://getcomposer.org/doc/04-schema.md#autoload
Заметь что композер поддерживает несколько вариантов автозагрузки.В первую очередь он расситан на код с неймспейсами, но можно и использовать с обычными классами, смотри пример после текста
> If you want to have a fallback directory where any namespace will be looked for, you can use an empty prefix like:
Неймспейсы, если что, это длинные префксы для классов которые помогают избежать проблем при наличии классов с одинаковыми именами. Мануал: http://php.net/manual/ru/language.namespaces.php
Хабр: http://habrahabr.ru/post/132736/
Ты уже делаешь второе, а не первое задание, так что с автозагрузкой и неймспейсами должен бы разобраться.
Надо сделать автозагрузчик (лучше всего через композер) и убрать лишние require_once.
> $app->container->singleton('newFile'
Это неправтльно. В синглетон мы кладем объекты, которые должны быть в 1 экземпляре. Если обратиться к синглетону второй раз то вернется тот же самый объект что был создан в первый. Потому делать синглтон для new File бессымсленно — он всегда будет возвроащать один и тот же объект.
Файл нужно создавать через new File, без синглтонов так как каждый раз тебе нужен новый объект.
> while ($mapper->iscodeUsed($file->getCode())) {
тут стоит добавить ограниение числа попыток. Хотя бы для защиты от заикливания на случай если ты ощибешься где-то.
Также тут уместнее не while, а do ... while.
Для защиты от выполнения кода хорошо бы не только использовать htaccess но и переименовывать файлы. А то бывают хостинги где команды php_flag и addType отключены. А вместе с ними отключается твоя защита (у одного анона так и получилось при загрузке на хостинг).
> $app->render('/header.html');
Этот вызов лучше перенести в шаблон /upload.html
> $id = $mapper->addFile($file);
Обычно принято делать по другому.Маппер не возвращает id а просто проставляет его в объект File.
> https://github.com/NotBadCode/Upload/blob/master/index.php#L86
> $file = $mapper->getFilebyID($id);
Нет проверки что такой файл есть в базе. Надо выдавать 404 (в Слиме есть для этого функция notFound ) при обращении с неправильным id файла.
> if (preg_match($RegExp, $file->getType())) {
лучше сделать метод $file>isImage()
> https://github.com/NotBadCode/Upload/blob/master/index.php#L105
> readfile("files/$code.$filename");
Тут тоже неправильно. Ты после отдачи файла начинаешь рисовать шаблон страницы. А надо завершить на этом работу скрипта.
> https://github.com/NotBadCode/Upload/blob/master/index.php#L122
> ?>
Не ставь ?> в конце, это источник багов так как за ним легко оставить пробел и сломать код.
Это надо удалить из репозитория, закоммитить, а потом внести содержимое папки в gitignore
> https://github.com/NotBadCode/Upload/blob/master/lib/pdo.php
Создание PDO надо сделать через синглтон в Слиме.
Про коду.
> singleton('newDM'
Лучше назвать нормально, filesMapper. Ведь это маппер для файлов? Ну так и называй его fileMapper.
Класс тоже стоит переименовать. Заодно научишься пользоваться функцей «найти и заменить во всех файлах». В Sublime это например Ctrl + Shift + H.
> require_once "/lib/Datamapper.php";
В php есть такая штука как автозагрузка. Это когда при обращению к несущестующему классу вызывается функция-автозагрузчик и она может приинклудить нужный файл с классом. Таким образом, require писать не требуется.
Теория: http://php.net/manual/ru/language.oop5.autoload.php
При исплоьзовании композера тебе вообще не надо писать автозагрузчик так как в композере он уже есть. Тебе надо лишь в composer.json написать в какой папке искать файлы (и сами файлы должны быть названы также как и класс). Вот доки на английском: https://getcomposer.org/doc/04-schema.md#autoload
Заметь что композер поддерживает несколько вариантов автозагрузки.В первую очередь он расситан на код с неймспейсами, но можно и использовать с обычными классами, смотри пример после текста
> If you want to have a fallback directory where any namespace will be looked for, you can use an empty prefix like:
Неймспейсы, если что, это длинные префксы для классов которые помогают избежать проблем при наличии классов с одинаковыми именами. Мануал: http://php.net/manual/ru/language.namespaces.php
Хабр: http://habrahabr.ru/post/132736/
Ты уже делаешь второе, а не первое задание, так что с автозагрузкой и неймспейсами должен бы разобраться.
Надо сделать автозагрузчик (лучше всего через композер) и убрать лишние require_once.
> $app->container->singleton('newFile'
Это неправтльно. В синглетон мы кладем объекты, которые должны быть в 1 экземпляре. Если обратиться к синглетону второй раз то вернется тот же самый объект что был создан в первый. Потому делать синглтон для new File бессымсленно — он всегда будет возвроащать один и тот же объект.
Файл нужно создавать через new File, без синглтонов так как каждый раз тебе нужен новый объект.
> while ($mapper->iscodeUsed($file->getCode())) {
тут стоит добавить ограниение числа попыток. Хотя бы для защиты от заикливания на случай если ты ощибешься где-то.
Также тут уместнее не while, а do ... while.
Для защиты от выполнения кода хорошо бы не только использовать htaccess но и переименовывать файлы. А то бывают хостинги где команды php_flag и addType отключены. А вместе с ними отключается твоя защита (у одного анона так и получилось при загрузке на хостинг).
> $app->render('/header.html');
Этот вызов лучше перенести в шаблон /upload.html
> $id = $mapper->addFile($file);
Обычно принято делать по другому.Маппер не возвращает id а просто проставляет его в объект File.
> https://github.com/NotBadCode/Upload/blob/master/index.php#L86
> $file = $mapper->getFilebyID($id);
Нет проверки что такой файл есть в базе. Надо выдавать 404 (в Слиме есть для этого функция notFound ) при обращении с неправильным id файла.
> if (preg_match($RegExp, $file->getType())) {
лучше сделать метод $file>isImage()
> https://github.com/NotBadCode/Upload/blob/master/index.php#L105
> readfile("files/$code.$filename");
Тут тоже неправильно. Ты после отдачи файла начинаешь рисовать шаблон страницы. А надо завершить на этом работу скрипта.
> https://github.com/NotBadCode/Upload/blob/master/index.php#L122
> ?>
Не ставь ?> в конце, это источник багов так как за ним легко оставить пробел и сломать код.
Это надо удалить из репозитория, закоммитить, а потом внести содержимое папки в gitignore
> https://github.com/NotBadCode/Upload/blob/master/lib/pdo.php
Создание PDO надо сделать через синглтон в Слиме.
> $word5
Странное название, что значит 5? Почему не просто $word?
> function numberToText($number) {
Тут куча унылой копипасты, а копипаста зло. Не надо делать склонение отдельно для рублей, тысяч, миллионов. Сделай одну универсальную функцию которая получает на вход число и 3 формы слова и возвращает нужную:
(17, соболь, соболя, соболей) -> 17 соболей
Соответственно исплоьзуя ее ты можешь избавиться от нечитаемой лапши в строках 140 - 160.
> \tif ($lastDigit == 1 && $lastDigits != 11) {
> $word5 = " рубль";
тут проще сразу ставить return " рубль"; . Зачем вообще переменную заводить?
> $arrNumber = preg_split ( "//", $number, - 1, PREG_SPLIT_NO_EMPTY );
С числами надо работать с помощью математиеских фукнций: floor, ceil, round а не строковых.
Это просто, вот 2 волшебных команды:
// получить последние 3 цифры числа:
echo 1234567 % 1000; // выведет 567
// получить число миллионов
echo floor(1234678 / 1000000); // выведет 12
Комбинируя их, можно получить что угодно.
> $arrNumber
Массивы принято назвать словом во множественном числе: $digits (цифры).
Код в строках 82-100 невозможно читать. Более того он явно сделан методом копипасты. Надо переделать по такомму алгоритму:
слова = пустой массив;
если в числе есть сотни {
добавляем слова для сотен;
}
если число оканчивается на 11-20 {
доабвляем нужные слова
} иначе {
добавляем десятки;
доабвляем единицы;
}
Еще, никогда не создавай таких сложных функций. Посмтри сколько в них действий, десятки если не сотни. Надо разбивать большие функции на маленькие (ксттаи эта задача как раз должна обучать этому).
Функция numberToText($number) должна работать примерно так:
если в числе есть миллионы {
доабвляем число миллионов;
}
если в числе есть тысячи {
доабвляем число тысяч;
}
если в числе есть единицы {
доабвляем число единиц;
}
Твой код может и рабоатет, но как решение он не годится. Его невозможно ни читать, ни поддерживать, огромные функции-простыни кода, куча переменных с непонятными названиями, надо все переделывать и упрощать.
Вот почитай еще эту статью: http://learn.javascript.ru/write-unmain-code
Если какие-то вопросы, задавай.
> $word5
Странное название, что значит 5? Почему не просто $word?
> function numberToText($number) {
Тут куча унылой копипасты, а копипаста зло. Не надо делать склонение отдельно для рублей, тысяч, миллионов. Сделай одну универсальную функцию которая получает на вход число и 3 формы слова и возвращает нужную:
(17, соболь, соболя, соболей) -> 17 соболей
Соответственно исплоьзуя ее ты можешь избавиться от нечитаемой лапши в строках 140 - 160.
> \tif ($lastDigit == 1 && $lastDigits != 11) {
> $word5 = " рубль";
тут проще сразу ставить return " рубль"; . Зачем вообще переменную заводить?
> $arrNumber = preg_split ( "//", $number, - 1, PREG_SPLIT_NO_EMPTY );
С числами надо работать с помощью математиеских фукнций: floor, ceil, round а не строковых.
Это просто, вот 2 волшебных команды:
// получить последние 3 цифры числа:
echo 1234567 % 1000; // выведет 567
// получить число миллионов
echo floor(1234678 / 1000000); // выведет 12
Комбинируя их, можно получить что угодно.
> $arrNumber
Массивы принято назвать словом во множественном числе: $digits (цифры).
Код в строках 82-100 невозможно читать. Более того он явно сделан методом копипасты. Надо переделать по такомму алгоритму:
слова = пустой массив;
если в числе есть сотни {
добавляем слова для сотен;
}
если число оканчивается на 11-20 {
доабвляем нужные слова
} иначе {
добавляем десятки;
доабвляем единицы;
}
Еще, никогда не создавай таких сложных функций. Посмтри сколько в них действий, десятки если не сотни. Надо разбивать большие функции на маленькие (ксттаи эта задача как раз должна обучать этому).
Функция numberToText($number) должна работать примерно так:
если в числе есть миллионы {
доабвляем число миллионов;
}
если в числе есть тысячи {
доабвляем число тысяч;
}
если в числе есть единицы {
доабвляем число единиц;
}
Твой код может и рабоатет, но как решение он не годится. Его невозможно ни читать, ни поддерживать, огромные функции-простыни кода, куча переменных с непонятными названиями, надо все переделывать и упрощать.
Вот почитай еще эту статью: http://learn.javascript.ru/write-unmain-code
Если какие-то вопросы, задавай.
И не копипасть. Повторяющиеся действия надо выносить в функции. А если в одной функции много кода, надо разбить ее на несколько маленьких.
>>442518
Модуль Апача который этим занимается это mod_rewrite.
хабр: http://habrahabr.ru/company/sprinthost/blog/129560/
подробные доки на англ:http://httpd.apache.org/docs/2.4/rewrite/
Сделал вот так:
<html>
<head>
<title>Блокировка поля</title>
<script type="text/javascript">
function agreeForm(f) {
// Если поставлен флажок, снимаем блокирование кнопки
if (f.errorLvl.checked) f.submit.disabled = 0
}
</script>
</head>
<body>
<form method="post" action="action.php">
<input type="radio" name="errorLvl" value="low" onclick="agreeForm(this.form)"> Низкая
<p><input type="submit" name="submit" value="Отправить" disabled>
</body>
</html>
Но оно работает только если одна радиокнопка. Если две или три (добавляем, например, строчку <input type="radio" name="errorLvl" value="high" onclick="agreeForm(this.form)"> Высокая<br>) - кнопка Отправить все время неактивна.
Как я понял, это из-затого, что у радиобатона одно имя. Если сделать несколько с разными - все работает, но меня такое не устраивает.
Спасибо, попробую переделать.
$pol="W";
$stmt = $this->mysqli->prepare("SELECT*FROM student WHERE pol=?");
$stmt->bind_param("s", $pol);
$stmt->execute();
$stmt->bind_result();
while ($stmt->fetch_assoc()) {
printf("%s\n", $pol);
}
Я хочу получить всех студентов у которых в графе пол стоит W, скажите что надо писать в
$stmt->bind_result()
Мне надо получить все данные по каждому из студентов, а не одну графу
Извините аноны, уже нашёл решение, но возник новый вопрос, допустим у меня есть такой код:
class news extends db {
public function getNews() {
$pol="M";
$stmt = $this->mysqli->prepare("SELECT id, name, lastname, pol FROM student WHERE pol=?");
$stmt->bind_param("s", $pol);
$stmt->execute();
$stmt->bind_result($id, $name, $lastname, $pol);
while($row = $stmt->fetch()){
//Здесь надо что то написать
}
}
}
Как мне получить вывод всех данных из таблицы, вот в этом куске кода:
while($row = $stmt->fetch()){
//Здесь надо что то написать
}
Вариант записать в цикле что то такое $arr[] = $row не подходит, так как цикл всё выводит только если записать переменными вроде:
echo "$id $name $lastname $pol"
В голову приходит только что то вроде этого:
$arr[$id]["name"] = $name;
$arr[$id]["lastname"] = $lastname;
$arr[$id]["pol"] = $pol;
А потом
return $arr;
И дальше работать уже через
$news = new news;
$news->getNews();
Но это уже как то совсем раково, верно?
Извините аноны, уже нашёл решение, но возник новый вопрос, допустим у меня есть такой код:
class news extends db {
public function getNews() {
$pol="M";
$stmt = $this->mysqli->prepare("SELECT id, name, lastname, pol FROM student WHERE pol=?");
$stmt->bind_param("s", $pol);
$stmt->execute();
$stmt->bind_result($id, $name, $lastname, $pol);
while($row = $stmt->fetch()){
//Здесь надо что то написать
}
}
}
Как мне получить вывод всех данных из таблицы, вот в этом куске кода:
while($row = $stmt->fetch()){
//Здесь надо что то написать
}
Вариант записать в цикле что то такое $arr[] = $row не подходит, так как цикл всё выводит только если записать переменными вроде:
echo "$id $name $lastname $pol"
В голову приходит только что то вроде этого:
$arr[$id]["name"] = $name;
$arr[$id]["lastname"] = $lastname;
$arr[$id]["pol"] = $pol;
А потом
return $arr;
И дальше работать уже через
$news = new news;
$news->getNews();
Но это уже как то совсем раково, верно?
И еще сразу вопрос - можно ли отправлять данные как в form, но не по кнопке, а через гиперссылку? То есть, например, есть ссылка в виде текстовой строки, по щелчке на ней идет выполнение action.php с параметрами, взятыми, например из текста этой ссылки (или еще откуда).
mb_internal_encoding ('utf-8');
но получаю:
Call to undefined function mb_internal_encoding()
В php.ini раскомментил extension=php_mbstring.dll , файл php_mbstring.dll в папке есть , но когда открываю phpinfo модуль mbstring отсутствует. Подскажите пожалуйста как правильно его установить.
С таблицами вроде разобрался, а вот насчет второго вопрос открытый.
http://jsfiddle.net/pg8pg864/
Спасибо за рецензию, а что такое в общих слова тайп хинтинг, я видел статью в мануале но как то не особо популярно объясняется.
>Обычно принято делать по другому.Маппер не возвращает id а просто проставляет его в объект File.
Объект в функцию разве не по ссылке передаётся, т.е. аддфайл изменит его?
>лучше сделать метод $file>isImage()
Если потом добавлять плеер то не логично
и у меня почему то не считается размер png, от чего это может быть?
И еще неудобно получилось, что при нажатии кнопки "Назад" в браузере, переходишь на предыдущую сортировку, а не на предыдущую страницу.
гетом передавай порядок - прямой или обратный
на страничке с также лови гет и формируй ссылку в зависимости от содержимого.
<?php
if ($_GET['order']=='desc') {$order='desc'} else {$order='asc'}
?>
<заголовок>
<a href='index.php?order='.$order>
</заголовок>
Точно, спасибо. Только if ($_GET['order']=='desc') {$order='asc'} else {$order='desc'}
http://jsfiddle.net/k4qhtx4u/ Переделал немного. Теперь вроде немного лучше, но все равно остается много вопросов:
Текст внутри картинки, по моему, имеет такую же прозрачность, как и блок в котором он находится. Как от этого избавится?
В маленьком окне ширина блока с текстом внутри картинки вылезает за саму картинку. Что за херня?
Как выравнить однёрку правее, чтобы она прилегала к тексту? Если изменить margin, то 2 3 4 будет внутри основного текста.
>Текст внутри картинки, по моему, имеет такую же прозрачность, как и блок в котором он находится. Как от этого избавится?
заверни весь текст в абзац с опасити=1, че ты?
тогда можно добавить классу субтайтл. большой надписи убрать прозрачность в этом случае нельзя никак.
Задачка про сумму прописью. Второй подход к снаряду. http://ideone.com/5BiRqV
Столкнулся с небольшим вопросом. Изначально я определял функцию spellingsOutp внутри функции inclineWord, inclineWord в отдельном файле в таком виде работала прекрасно. Когда поместил это непосредственно в программу, то фатал еррор нельзя переопределить, кровь, кишки. Вынес spellingsOut так сказать в корень, и все стало ок. Это почему?
Ошибка в том что не установлен (или не разрешен) модуль openssl. Вывести список подключенных модулей можно командой
php -m
Получить подробную информацию о текущих настройках php командой
php -i
Чтобы разрешить расширение openssl, надо открыть php.ini (если у тебя их несколько то тот который используется в командной строке) и раскомментировать или дописать строку extension = php_openssl.dll или как-то так.
Мануал про установку расширений на windows http://php.net/manual/ru/install.windows.extensions.php
В твоем случае openssl скорее всего идет в комплекте с php просто не разрешен.
Также, я не уверен но возможно что под денвером надо открывать не обычную командную строку, а через меню денвера, чтобы php получил актуальные настройки. Но я не уверен.
Ну и заметь что несмотря на отсутствие openssl композер все же смог скачать библиотеки другим способом.
Библиотека openssl нужна для установки защищенного соединения с сервером.
Таблицы предназначены для вывода табличных данных. Например, расписание турнира или таблица стран и их столиц.
Лет 15 назад, когда HTML/CSS был гораздо менее развит, таблицы от безвыходности использовали для верстки сайтов (а прозрачные картинки для создания полей и оступов). Но это очень плохой и неудобный способ, CSS дает гораздо больше возможностей потому никто так не делает.
На таблицах сейчас верстают только HTML-письма так как почтовые сервисы вырезают многие правила CSS.
Если ты говоришь про верстку таблицами, ты скорее всего учился по очень старому учебнику? Выбрось его и найди нормальный.
Напомню, что у нас есть хорошие задачи по HTML/CSS (ссылка в ОП посте) которые помогут найти пробелы в знаниях и научат тебя верстать средствами CSS.
>>442531
Под какой ОС? Windows?
Скачать можно тут https://www.apachelounge.com/download/ в архиве modules-2.4-win32-VC11.zip (или win64) но они возможно будут работать только с Апачом скачанным с Apachelounge. С другим — не факт. Заметь что они для версии 2.4.
Под Линукс зависит от дистрибутива, в дебиане/убунту ищешь расширение командой
apt-cache search sendfile
и ставишь командой
sudo apt-get install название-пакета
Таблицы предназначены для вывода табличных данных. Например, расписание турнира или таблица стран и их столиц.
Лет 15 назад, когда HTML/CSS был гораздо менее развит, таблицы от безвыходности использовали для верстки сайтов (а прозрачные картинки для создания полей и оступов). Но это очень плохой и неудобный способ, CSS дает гораздо больше возможностей потому никто так не делает.
На таблицах сейчас верстают только HTML-письма так как почтовые сервисы вырезают многие правила CSS.
Если ты говоришь про верстку таблицами, ты скорее всего учился по очень старому учебнику? Выбрось его и найди нормальный.
Напомню, что у нас есть хорошие задачи по HTML/CSS (ссылка в ОП посте) которые помогут найти пробелы в знаниях и научат тебя верстать средствами CSS.
>>442531
Под какой ОС? Windows?
Скачать можно тут https://www.apachelounge.com/download/ в архиве modules-2.4-win32-VC11.zip (или win64) но они возможно будут работать только с Апачом скачанным с Apachelounge. С другим — не факт. Заметь что они для версии 2.4.
Под Линукс зависит от дистрибутива, в дебиане/убунту ищешь расширение командой
apt-cache search sendfile
и ставишь командой
sudo apt-get install название-пакета
Тебе надо изучить яваскрипт, DOM и jQuery наверно сначала. как иначе писать скрипт не понимая языка и используемых библиотек?
>>442591
Если есть несколько элементов с одним именем то в
f.elements.name
будет массив этих элементов. Опять же, тебе явно надо изучать DOM потому что иначе ты будешь на каждую мелочь кучу времени тратить.
Это описано тут например: http://learn.javascript.ru/traversing-dom#формы
Без изучения теории ты ничего не добьешься.
Зачем ты используешь привязку переменных? Это в первую очередь рассчитано на случаи вроде использования хранимых процедур.
В mysqli есть метод get_result: http://php.net/manual/ru/mysqli-stmt.get-result.php
Он вернет объект-результат у которого есть методы для получения поля, массива-записи, или массива всех записей сразу.
Также, классы пишутся с большой буквы (ссылка на стандарт: http://www.php-fig.org/psr/psr-1/ru/ )
Также, может быть тебе будет интересно почитать мой урок про паттерны работы с БД: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
>>442622
когда опрелеляешь font size рядом всегда определяй line-height. Вот тут подробнее http://learn.javascript.ru/font-size-line-height
> p.content {
>\tpadding-left: 120px;
А если я добавлю список и картинку? Смотри что получится: http://jsfiddle.net/vzer3Lpm/2/
Поля надо делать на родителе, а не на детях.
> p.note
Это избыточный селектор. Достаточно просто .note .
p.note пишут когда хотят задать особые правила если класс note применен к тегу p.
>>442629
Тебе надо сначала изучить язык php. Так как если бы ты его знал то ответ был бы очевиден: использовать какой-нибудь другой вид цикла или прописать поля прямо в шаблоне.
Надо сначала изучать php потом изучать sql и базы данных, потом библиотеки вроде mysqli/pdo.
А если ты берешь учебник или видеокурс, проматываешь сразу на середину и копируешь строчки не понимая что они делают, ты ничего не добьешься. Программирование так не работает.
> Я же не знаю, сколько строк у нее будет.
Во-первых, ты знаешь. Ты же должен знать сколько у тебя в таблице колонок. Во-вторых, в html и не требуется писать число столбцов/колонок.
> можно ли отправлять данные как в form, но не по кнопке, а через гиперссылку?
Можно сделать средствами CSS чтобы кнопка выглядела как ссылка. Но вообще это бред какой-то. Ссылка ведет на другую страницу и какой смысл делать ссылку-которая-на-самом-деле-кнопка, я не понмиаю. Чтобы пользователя запутать?
Зачем ты используешь привязку переменных? Это в первую очередь рассчитано на случаи вроде использования хранимых процедур.
В mysqli есть метод get_result: http://php.net/manual/ru/mysqli-stmt.get-result.php
Он вернет объект-результат у которого есть методы для получения поля, массива-записи, или массива всех записей сразу.
Также, классы пишутся с большой буквы (ссылка на стандарт: http://www.php-fig.org/psr/psr-1/ru/ )
Также, может быть тебе будет интересно почитать мой урок про паттерны работы с БД: https://gist.github.com/codedokode/c4cbc4d7dc8e45ea074a
>>442622
когда опрелеляешь font size рядом всегда определяй line-height. Вот тут подробнее http://learn.javascript.ru/font-size-line-height
> p.content {
>\tpadding-left: 120px;
А если я добавлю список и картинку? Смотри что получится: http://jsfiddle.net/vzer3Lpm/2/
Поля надо делать на родителе, а не на детях.
> p.note
Это избыточный селектор. Достаточно просто .note .
p.note пишут когда хотят задать особые правила если класс note применен к тегу p.
>>442629
Тебе надо сначала изучить язык php. Так как если бы ты его знал то ответ был бы очевиден: использовать какой-нибудь другой вид цикла или прописать поля прямо в шаблоне.
Надо сначала изучать php потом изучать sql и базы данных, потом библиотеки вроде mysqli/pdo.
А если ты берешь учебник или видеокурс, проматываешь сразу на середину и копируешь строчки не понимая что они делают, ты ничего не добьешься. Программирование так не работает.
> Я же не знаю, сколько строк у нее будет.
Во-первых, ты знаешь. Ты же должен знать сколько у тебя в таблице колонок. Во-вторых, в html и не требуется писать число столбцов/колонок.
> можно ли отправлять данные как в form, но не по кнопке, а через гиперссылку?
Можно сделать средствами CSS чтобы кнопка выглядела как ссылка. Но вообще это бред какой-то. Ссылка ведет на другую страницу и какой смысл делать ссылку-которая-на-самом-деле-кнопка, я не понмиаю. Чтобы пользователя запутать?
У тебя в окне с результатами горизонтальная полоса прокрутки и прямоугольник уходит за край экрана. Ты ее видишь? Это очень некрасиво.
Почему? Давай вспоминать боксовую модель:
> \twidth: 99%;
> padding: 10px;
> border:1px solid black;
В сумме 99% + 22 px очевидно дают больше 100% и прямоугольник вываливается вправо. Это неправильо, смешивать пиксели и проценты.
Далее, вот это:
> display: table;
Зачем? Только чтобы блок охватывал флоаты внутри? Для этого есть более удобный клеарфикс, ссылка на который дана в подсказках к заданию.
Ты из-за исплоьзования table не можешь поставить width auto и блок вываливается за край.
> font-size: 14px;
где line-height?
> \tfloat: left;
>\tdisplay: inline;
float всегда ставит display = block
Если в текст добавить заголовки, то они почему-то уезжают влево: http://jsfiddle.net/rt3raq1m/1/
Надо чтобы в текст можно было добавлять заголвоки, картинки, цитаты, таблицы, списки и ничего не уезжало.
У тебя в окне с результатами горизонтальная полоса прокрутки и прямоугольник уходит за край экрана. Ты ее видишь? Это очень некрасиво.
Почему? Давай вспоминать боксовую модель:
> \twidth: 99%;
> padding: 10px;
> border:1px solid black;
В сумме 99% + 22 px очевидно дают больше 100% и прямоугольник вываливается вправо. Это неправильо, смешивать пиксели и проценты.
Далее, вот это:
> display: table;
Зачем? Только чтобы блок охватывал флоаты внутри? Для этого есть более удобный клеарфикс, ссылка на который дана в подсказках к заданию.
Ты из-за исплоьзования table не можешь поставить width auto и блок вываливается за край.
> font-size: 14px;
где line-height?
> \tfloat: left;
>\tdisplay: inline;
float всегда ставит display = block
Если в текст добавить заголовки, то они почему-то уезжают влево: http://jsfiddle.net/rt3raq1m/1/
Надо чтобы в текст можно было добавлять заголвоки, картинки, цитаты, таблицы, списки и ничего не уезжало.
> В php.ini раскомментил extension=php_mbstring.dll , файл php_mbstring.dll в папке есть , но когда открываю phpinfo модуль mbstring отсутствует. Подскажите пожалуйста как правильно его установить.
Апач перезапускал? php ведь сам новые настройки не увидит.
>>442658
Да, ты правильно заметил. Подпись съезжает так как сверстана неправильно.
> bottom:-250px;
Ты предполагаешь что высота картинки будет ровно 250px. С чего бы это? Надо чтобы работало с картинкой любой высоты.
Вообще, старайся как можно меньше прописывать абсолютные величины и как можно больше определять автоматически. иначе замучаешься потом поддерживать такую верстку.
>>442659
Тайп хинтинг позволяет указать что аргумент функции должен быть определенного типа. Если передать аргумент другого типа, скрипт завершится с ошибкой. Это делает твой код гораздо понятнее и надежнее.
Можно указать несклоько вариантов:
— имя класса или интерфейса (должен быть передан объект этого класса или его наследник)
— array (должен быть передан массив)
— callable (должен быть передан указатель на функцию, виды указателей описаны в мануале http://php.net/manual/ru/language.types.callable.php )
codedokode at gmail.com
Но ты можешь и скриншоты выложить. Так даже может быть удобнее будет, не надо никуда логиниться.
>>442691
> Объект в функцию разве не по ссылке передаётся, т.е. аддфайл изменит его?
Да. Это нам и надо.
Объекты не копируются при присваивании или передаче в функцию, просто передается ссылка на объект. Смотри:
$a = new X;
$b = $a;
Тут 2 переменных $b и $a содержат ссылки на один и тот же объект. С другими типами (массивы, строки, числа) команда $a = $b создает копию, а объекты передаются почти как по ссылке. Мануал: http://php.net/manual/ru/language.oop5.references.php
Чтобы сделать копию (клон) объекта надо использовать оператор clone. В 99% случаев он тебе не нужен, тебе нужно именно передать ссылку на объект.
> и у меня почему то не считается размер png, от чего это может быть?
Не знаю, но я не думаю что дело в формате файла. Ведь размер файла никак не связан с его расширением. Должно либо для всех файлов работать либо для всех не работать.
>>442693
Надо при выводе ссылки если по этой колонке идет сортировка, подставлять в нее другой параметр.
>>442694
так и должно быть. Если ты с 5-й страницы перейдешь на 2-ю и нажмешь «назад» то вернешься на пятую, а не на первую.
>>442850
> Текст внутри картинки, по моему, имеет такую же прозрачность, как и блок в котором он находится. Как от этого избавится?
нужно не использовать opacity, а просто поставить полупрозрачный фон. Описание:
http://htmlbook.ru/blog/poluprozrachnyy-fon
http://htmlbook.ru/css/value/color
RGBA работает в IE9+ и в современных бюраузерах, так что проблем с ним нет (ну даже если не работает, пусть в старом браузере фон будет непрозрачным — это приемлемо и текст читать не мешает).
Потому я бы поставил 2 правила:
background: непрозрачный фон для старых браузеров;
backgorund: прозрачный для новых;
Старые браузеры поймут только первое правило, а новые оба и второе переопределит первое.
> В маленьком окне ширина блока с текстом внутри картинки вылезает за саму картинку. Что за херня?
Сделай чтобы переносилось как-то или текст обрезался. Главное чтобы картинка уменьшалась при уменьшении ширины окна.
codedokode at gmail.com
Но ты можешь и скриншоты выложить. Так даже может быть удобнее будет, не надо никуда логиниться.
>>442691
> Объект в функцию разве не по ссылке передаётся, т.е. аддфайл изменит его?
Да. Это нам и надо.
Объекты не копируются при присваивании или передаче в функцию, просто передается ссылка на объект. Смотри:
$a = new X;
$b = $a;
Тут 2 переменных $b и $a содержат ссылки на один и тот же объект. С другими типами (массивы, строки, числа) команда $a = $b создает копию, а объекты передаются почти как по ссылке. Мануал: http://php.net/manual/ru/language.oop5.references.php
Чтобы сделать копию (клон) объекта надо использовать оператор clone. В 99% случаев он тебе не нужен, тебе нужно именно передать ссылку на объект.
> и у меня почему то не считается размер png, от чего это может быть?
Не знаю, но я не думаю что дело в формате файла. Ведь размер файла никак не связан с его расширением. Должно либо для всех файлов работать либо для всех не работать.
>>442693
Надо при выводе ссылки если по этой колонке идет сортировка, подставлять в нее другой параметр.
>>442694
так и должно быть. Если ты с 5-й страницы перейдешь на 2-ю и нажмешь «назад» то вернешься на пятую, а не на первую.
>>442850
> Текст внутри картинки, по моему, имеет такую же прозрачность, как и блок в котором он находится. Как от этого избавится?
нужно не использовать opacity, а просто поставить полупрозрачный фон. Описание:
http://htmlbook.ru/blog/poluprozrachnyy-fon
http://htmlbook.ru/css/value/color
RGBA работает в IE9+ и в современных бюраузерах, так что проблем с ним нет (ну даже если не работает, пусть в старом браузере фон будет непрозрачным — это приемлемо и текст читать не мешает).
Потому я бы поставил 2 правила:
background: непрозрачный фон для старых браузеров;
backgorund: прозрачный для новых;
Старые браузеры поймут только первое правило, а новые оба и второе переопределит первое.
> В маленьком окне ширина блока с текстом внутри картинки вылезает за саму картинку. Что за херня?
Сделай чтобы переносилось как-то или текст обрезался. Главное чтобы картинка уменьшалась при уменьшении ширины окна.
> Как выравнить однёрку правее, чтобы она прилегала к тексту? Если изменить margin, то 2 3 4 будет внутри основного текста.
А какое свойство отвечает за выравнивание текста внутри блока? text-align может быть?
> font-family: 'Times New Roman';
Надо добавлять в конец fallback шрифт: http://htmlbook.ru/css/font-family
> figure{
> \tposition: absolute;
AP (абс. позиционированные) элементы вырываются из потока и не занимают в нем места. Если после картинки идет текст, он окажется под картинкой. Это неправильно. Если ты этого не знал то перечитай внимательно учебник http://softwaremaniacs.org/blog/2005/08/03/css-layout-positioning/
Далее, под черной подписью у тебя 3-4 пикселя пустого места. Почему? Потому что img это inline элемент который выравнивается по базовой линии. Почитай
http://xiper.net/collect/html-and-css-tricks/content/img-in-the-block
http://habrahabr.ru/post/51140/
> figcaption{
> \twidth: 340px;
Не, так не пойдет. Надо чтобы работало с картинками неизвестного размера (например они могут браться из базы данных и заранее размер неизвестен).
У меня такое ощущение, что ты ставишь свойства наугад, в надежде что заработает. Это неправильно. надо понимать эффект от разных свойств и ставить те, которые нужны.
Например, у нас задача чтобы блок с картинкой (figure) с одной стороны зависел от размеров картинки, с другой стороны не превышал ширины родителя.
Давай подумаем, а в каких случаях ширина элемента зависит от содержимого? Ровно в трех: display: table/table-cell, display: inline-block/inline, float.
Table плох тем что в нем не работает абсолютное позиционирование. Ты не можешь позиционировать элементы относительно ячейки или таблицы.
Float плох тем что он выносится вбок из потока и текст следующий за ним подтягивается вверх, если к нему не применить clear.
Inline-block выглядит тут разумным вариантом.
Inline тут не подойдет, так как годится только для выделения слов в строке и например не умеет растягивать свою высоту по содержимому.
Таким образом, мы получаем что нам подойдет inline-block, который по умолчанию растягивается под размеры содержимого.
Вот примерно так и надо расуждать.
> Как выравнить однёрку правее, чтобы она прилегала к тексту? Если изменить margin, то 2 3 4 будет внутри основного текста.
А какое свойство отвечает за выравнивание текста внутри блока? text-align может быть?
> font-family: 'Times New Roman';
Надо добавлять в конец fallback шрифт: http://htmlbook.ru/css/font-family
> figure{
> \tposition: absolute;
AP (абс. позиционированные) элементы вырываются из потока и не занимают в нем места. Если после картинки идет текст, он окажется под картинкой. Это неправильно. Если ты этого не знал то перечитай внимательно учебник http://softwaremaniacs.org/blog/2005/08/03/css-layout-positioning/
Далее, под черной подписью у тебя 3-4 пикселя пустого места. Почему? Потому что img это inline элемент который выравнивается по базовой линии. Почитай
http://xiper.net/collect/html-and-css-tricks/content/img-in-the-block
http://habrahabr.ru/post/51140/
> figcaption{
> \twidth: 340px;
Не, так не пойдет. Надо чтобы работало с картинками неизвестного размера (например они могут браться из базы данных и заранее размер неизвестен).
У меня такое ощущение, что ты ставишь свойства наугад, в надежде что заработает. Это неправильно. надо понимать эффект от разных свойств и ставить те, которые нужны.
Например, у нас задача чтобы блок с картинкой (figure) с одной стороны зависел от размеров картинки, с другой стороны не превышал ширины родителя.
Давай подумаем, а в каких случаях ширина элемента зависит от содержимого? Ровно в трех: display: table/table-cell, display: inline-block/inline, float.
Table плох тем что в нем не работает абсолютное позиционирование. Ты не можешь позиционировать элементы относительно ячейки или таблицы.
Float плох тем что он выносится вбок из потока и текст следующий за ним подтягивается вверх, если к нему не применить clear.
Inline-block выглядит тут разумным вариантом.
Inline тут не подойдет, так как годится только для выделения слов в строке и например не умеет растягивать свою высоту по содержимому.
Таким образом, мы получаем что нам подойдет inline-block, который по умолчанию растягивается под размеры содержимого.
Вот примерно так и надо расуждать.
opacity применяется ко всему содержимом внтури и твой подход не сработает, проверь сам.
Точно также нельзя отменить text-decoration: underline внутри если оно задано на родителе.
>>442883
Не поможет
>>442924
> Изначально я определял функцию spellingsOutp внутри функции inclineWord
зачем? В какой сиитуации это вообще может понадобиться? Никогда не определяй функции внутри функций (кроме анонимных).
Ошибка так как при втором вызове функции inclineWord она пытается второй раз создать spellingsOutp, а создать 2 функици с одинаковым названием нельзя.
> spellingsOut($int, $array)
Не называй переменную array так как это ничего не значит. Называй например $words.
Вот тут про это написано: http://learn.javascript.ru/write-unmain-code#будьте-абстрактны-при-выборе-имени
> if ($int % 10 == 0 || ($int % 100 > 10 && $int % 100 < 20) || ($int % 10 > 4 && $int % 10 < 10)) {
Вообще этот if можно было и не писать
> array_push ( $words,
Короче и нагляднее писать
$words[] = ....;
Еще, пробел около скобок при вызове функции принято не ставить:
someFunction($a, $b, $c);
Так, вообще в сравнении с прошлой версией разница как день и ночь, стало намного аккуратнее и понятнее. Исправь мелкие замечания и я думаю, задача будет решена.
opacity применяется ко всему содержимом внтури и твой подход не сработает, проверь сам.
Точно также нельзя отменить text-decoration: underline внутри если оно задано на родителе.
>>442883
Не поможет
>>442924
> Изначально я определял функцию spellingsOutp внутри функции inclineWord
зачем? В какой сиитуации это вообще может понадобиться? Никогда не определяй функции внутри функций (кроме анонимных).
Ошибка так как при втором вызове функции inclineWord она пытается второй раз создать spellingsOutp, а создать 2 функици с одинаковым названием нельзя.
> spellingsOut($int, $array)
Не называй переменную array так как это ничего не значит. Называй например $words.
Вот тут про это написано: http://learn.javascript.ru/write-unmain-code#будьте-абстрактны-при-выборе-имени
> if ($int % 10 == 0 || ($int % 100 > 10 && $int % 100 < 20) || ($int % 10 > 4 && $int % 10 < 10)) {
Вообще этот if можно было и не писать
> array_push ( $words,
Короче и нагляднее писать
$words[] = ....;
Еще, пробел около скобок при вызове функции принято не ставить:
someFunction($a, $b, $c);
Так, вообще в сравнении с прошлой версией разница как день и ночь, стало намного аккуратнее и понятнее. Исправь мелкие замечания и я думаю, задача будет решена.
>// неправильное определение свойств:
>public $var1 = 'hello ' . 'world';
Почему нельзя определять свойства символьно?
нельзя писать выражения. Нужно сразу писать конкретное значение например
public $x= 1;
а так нельзя:
public $y = 2 + 2;
ОП, напиши если не удобно будет читать эту простыню, я разделю тогда и залью на гитхаб
http://ideone.com/KYBGOW
>Нет. Абстрактным может быть класс (это значит что нельзя создать объект такого класса) либо метод (это метод без тела, который обязаны реализовать наследники класса).
А как быть тогда с don't reapet yourself здесь?
>А то что делать если мы решили повысить работника с 1 до 2 ранга?
А что делать если мы решили что искусственный интеллект справляется лучше чем "работник"? Давай лучше будем отталкиваться от конкретной задачи. И вообще, для решения этой задачи мне придется внести новую переменную $newSolary, что будет масло масляное - не одобряю.
>>443113
>Если ты говоришь про верстку таблицами, ты скорее всего учился по очень старому учебнику?
Не, я просто ничего не знаю, это остатки 10+ летней давности школьных знаний.
>>443115
>Тебе надо изучить яваскрипт, DOM и jQuery наверно сначала. как иначе писать скрипт не понимая языка и используемых библиотек?
Я про то, что мне непонятно само слово.
>А какое свойство отвечает за выравнивание текста внутри блока? text-align может быть?
Ну я это первым делом и попробовал, но раз уж я тут, значит это не помогло.
Вот http://jsfiddle.net/k4qhtx4u/2/
Спасибо, учту.
>пробел около скобок при вызове функции принято не ставить
Мне Eclipse так раскидывает, при определении пробелов нет, при вызове - есть. В настройках форматирования стоит PHP Conventions, стоит переключить на PSR-2?
> А как быть тогда с don't reapet yourself здесь?
Здесь проблемы нет. Ты в абстрактном классе определяешь свойство, а в наследниках переопределяешь его с добавлением значения.
> Давай лучше будем отталкиваться от конкретной задачи.
> И вообще, для решения этой задачи мне придется внести новую переменную $newSolary, что будет масло масляное - не одобряю.
По моему либо ты либо я что-то не поняли. У работника есть свойства вроде ранг, базовая ставка и тд. Хранить вычисляемые из них свойства вроде зарплаты (newSolary) незачем так как их в любой момент можно посчитать с помощью метода. Соответственно то, что я предлагаю это упрощение, а не усложнение. Я предлагаю удалить свойства вроде newSolary и упростить код.
> $this->rang = $rang;
> \t$this->newSolary = $this->calculateSolary( );
Это нехороший код. Базовый класс ничего не знает о своих потомках и не должен обращаться к свойствам которых у него нету.
То есть ты должен объявить свойства вроде rang у базового класса.
Вот это вот свойство
> public $rang;
не надо копипастить, нужно один раз его объявить на базовом классе.
Далее, ты зачем-то по несколько раз присваиваешь свойство в нескольких местах. Это запутывает код:
> $this->newSolary = $this->calculateSolary( );
> case 1:
>\t\t\t\t$this->newSolary = $this->solary;
> Не уверен в необхадимости этой строки, ведь это свойство и так изменяется само по себе.
> По сему назривают следующие вопросы:
> 1. Необхадимо ли передача этого параметра?
лучше вообще убрать свойство newSolary. Зачем его вообще хранить в объекте? Используй обычную переменную.
> 2. Будет ли правильнее создание заместо этого параметра создать обычную переменную внутри функции и далее, её уже передавать?
думаю, да.
> public function calculateSolary() {
> $this->newSolary = $this->newSolary + ($this->newSolary x 0.50);
Это неудачно сделанная функция. Если ее вызвать несколько раз подряд, то зарплата вырастет в несколько раз. Такого не должно быть. Такие функции это как мины на которые легко может наступить любой программист. Ведь он ожидает что функция работает правильно сколько бы раз ее не вызывали.
Потому я тебе советую удалить это свойство newSolary и проблема исчезнет сама собой.
> public function __construct() {
>\t\t$this->addManagersToDepartment( );
Это не очень логично: почему департамент при создании добавляет сам в себя работников? лучше сделать, чтобы создавался пустой департамент и в него поле этого можно было добавлять работников.
Ты не должен делать нелогичные вещи только потому, что в задаче «этого не требуется». Да, в задаче не требуется создавать пустой департамент или менять ранг работника, но правильно написанный ООП код позволяет это сделать без изменений. А если не позволяет то скорее всего с кодом проблемы.
Хорошо написанный класс работника предполагает что мы можем создать работника, задавать ему любые разумные значения свойств (в идеальном коде мы не можем обращаться к свойствам напрямую, а только через методы которые выкинут исключение при попытке задать неправильный ранг например) и получать информацию например о выпитом кофе или выплаченной зарплате.
Хорошо написанный класс департамента позволяет создать департамент, добавить в него любое количество работников, назначить босса (в идеале при назначении нового босса старый должен переставать им быть) и посчитать общий расход кофе или число произведенных страниц.
Мне кажется, по этой причине лучше добавлять работников снаружи. Ну и убрать лишние свойства вроде public $expenses = array( ); так как эту информацию всегда можно посчитать и незачем ее хранить.
Насчет департаментов, можно не делать классы для каждого департамента, а просто сделать один класс департамента. Они в принципе различаются только названием.
Далее, тут ошибка:
> $calculateManagersNumber = count($this->employees[$this->nameOfDepartment]['Managers']);
> \t\t$calculateMarketersNumber = count($this->employees[$this->nameOfDepartment]['Marketers']);
У тебя базовый класс департамента откуда-то знает какие именно типы работников существуют. Это значит что если мы захотим добавить 5-ю профессию, мы должны будем переписать весь код. Это нехорошо. Надо чтобы для добавления новой ппрофессии достаточно было сделать 2 вещи:
- добавить новый класс професссии
- создать объекты этого класса (работников) и добавить в департамент
При этом код класса Департамент менять не требуется. В этом и преимущество ООП, что мы разбиваем код на независимые классы и нам не надо весь его переписывать при любом изменении. У тебя пока код не соответствует этому критерию, надо чтобы соответствовал.
Если тебе сложно сразу понять как надо сделать, давай ты напишешь что-то вроде схемы, какие классы, свойства и методы ты хочешь сделать, а я скажу правильно ли все или что-то надо исправить. Или можешь сразу код менять, если хочешь.
Аналогично, в депараменте не может быть методов вроде addMarketersToDepartment так как он не знает какие вообще профессии существуют. Он знает что есть базовый класс Employee и этого знания достаточно. И мы можем добавлять любое число профессий не меняя ни строчки кода в Департаменте.
> $this->employees[$this->nameOfDepartment]['Leader'][]
Тут тоже усложнение. Зачем городить трехмерный массив? Сделай свойство employees которое будет массивом объектов, и свойство leader которое хранит босса. Этого достаточно.
Если тебе что-то неясно или у тебя есть своя точка зрения, напиши, обсудим.
> А как быть тогда с don't reapet yourself здесь?
Здесь проблемы нет. Ты в абстрактном классе определяешь свойство, а в наследниках переопределяешь его с добавлением значения.
> Давай лучше будем отталкиваться от конкретной задачи.
> И вообще, для решения этой задачи мне придется внести новую переменную $newSolary, что будет масло масляное - не одобряю.
По моему либо ты либо я что-то не поняли. У работника есть свойства вроде ранг, базовая ставка и тд. Хранить вычисляемые из них свойства вроде зарплаты (newSolary) незачем так как их в любой момент можно посчитать с помощью метода. Соответственно то, что я предлагаю это упрощение, а не усложнение. Я предлагаю удалить свойства вроде newSolary и упростить код.
> $this->rang = $rang;
> \t$this->newSolary = $this->calculateSolary( );
Это нехороший код. Базовый класс ничего не знает о своих потомках и не должен обращаться к свойствам которых у него нету.
То есть ты должен объявить свойства вроде rang у базового класса.
Вот это вот свойство
> public $rang;
не надо копипастить, нужно один раз его объявить на базовом классе.
Далее, ты зачем-то по несколько раз присваиваешь свойство в нескольких местах. Это запутывает код:
> $this->newSolary = $this->calculateSolary( );
> case 1:
>\t\t\t\t$this->newSolary = $this->solary;
> Не уверен в необхадимости этой строки, ведь это свойство и так изменяется само по себе.
> По сему назривают следующие вопросы:
> 1. Необхадимо ли передача этого параметра?
лучше вообще убрать свойство newSolary. Зачем его вообще хранить в объекте? Используй обычную переменную.
> 2. Будет ли правильнее создание заместо этого параметра создать обычную переменную внутри функции и далее, её уже передавать?
думаю, да.
> public function calculateSolary() {
> $this->newSolary = $this->newSolary + ($this->newSolary x 0.50);
Это неудачно сделанная функция. Если ее вызвать несколько раз подряд, то зарплата вырастет в несколько раз. Такого не должно быть. Такие функции это как мины на которые легко может наступить любой программист. Ведь он ожидает что функция работает правильно сколько бы раз ее не вызывали.
Потому я тебе советую удалить это свойство newSolary и проблема исчезнет сама собой.
> public function __construct() {
>\t\t$this->addManagersToDepartment( );
Это не очень логично: почему департамент при создании добавляет сам в себя работников? лучше сделать, чтобы создавался пустой департамент и в него поле этого можно было добавлять работников.
Ты не должен делать нелогичные вещи только потому, что в задаче «этого не требуется». Да, в задаче не требуется создавать пустой департамент или менять ранг работника, но правильно написанный ООП код позволяет это сделать без изменений. А если не позволяет то скорее всего с кодом проблемы.
Хорошо написанный класс работника предполагает что мы можем создать работника, задавать ему любые разумные значения свойств (в идеальном коде мы не можем обращаться к свойствам напрямую, а только через методы которые выкинут исключение при попытке задать неправильный ранг например) и получать информацию например о выпитом кофе или выплаченной зарплате.
Хорошо написанный класс департамента позволяет создать департамент, добавить в него любое количество работников, назначить босса (в идеале при назначении нового босса старый должен переставать им быть) и посчитать общий расход кофе или число произведенных страниц.
Мне кажется, по этой причине лучше добавлять работников снаружи. Ну и убрать лишние свойства вроде public $expenses = array( ); так как эту информацию всегда можно посчитать и незачем ее хранить.
Насчет департаментов, можно не делать классы для каждого департамента, а просто сделать один класс департамента. Они в принципе различаются только названием.
Далее, тут ошибка:
> $calculateManagersNumber = count($this->employees[$this->nameOfDepartment]['Managers']);
> \t\t$calculateMarketersNumber = count($this->employees[$this->nameOfDepartment]['Marketers']);
У тебя базовый класс департамента откуда-то знает какие именно типы работников существуют. Это значит что если мы захотим добавить 5-ю профессию, мы должны будем переписать весь код. Это нехорошо. Надо чтобы для добавления новой ппрофессии достаточно было сделать 2 вещи:
- добавить новый класс професссии
- создать объекты этого класса (работников) и добавить в департамент
При этом код класса Департамент менять не требуется. В этом и преимущество ООП, что мы разбиваем код на независимые классы и нам не надо весь его переписывать при любом изменении. У тебя пока код не соответствует этому критерию, надо чтобы соответствовал.
Если тебе сложно сразу понять как надо сделать, давай ты напишешь что-то вроде схемы, какие классы, свойства и методы ты хочешь сделать, а я скажу правильно ли все или что-то надо исправить. Или можешь сразу код менять, если хочешь.
Аналогично, в депараменте не может быть методов вроде addMarketersToDepartment так как он не знает какие вообще профессии существуют. Он знает что есть базовый класс Employee и этого знания достаточно. И мы можем добавлять любое число профессий не меняя ни строчки кода в Департаменте.
> $this->employees[$this->nameOfDepartment]['Leader'][]
Тут тоже усложнение. Зачем городить трехмерный массив? Сделай свойство employees которое будет массивом объектов, и свойство leader которое хранит босса. Этого достаточно.
Если тебе что-то неясно или у тебя есть своя точка зрения, напиши, обсудим.
> А что делать если мы решили что искусственный интеллект справляется лучше чем "работник"?
Сделаем класс class AI extends Employee и у него в методе getSalary() напишем return 0 (денег то он не просит).
>>443203
> считаю количество строк, делю их на желаемое количество строк на одной странице
ну так это всего 2 строки. Вообще альтернативный способ есть: можно создать объект для управления постраничной навигацией (Pagination). Ты при создании даешь ему число записей, число записей на одной странице, номер страницы, шаблон ссылки. а он рассчитывает число страниц, генерирует ссылки и все прочее.
> Я про то, что мне непонятно само слово.
Ну ок
> инлайн до добра не доводит.
Имеется в виду inline обработчик события, заданный с помощью аттрибута onXXX у тега.
> Юзай жикверя,
jQuery — библиотека для работы с DOM. Юзай= используй (use)
> вешай действие.
Назначь обработчик для события.
>>443237
А может ли быть такое что у тебя на компьютере несколько php.ini и ты включил расширение не в том файле? Увидеть исползуемый файл можно выведя phpinfo(), там написано где именно лежит php.ini
>>443240
Это не помогло потому что у тебя ширина флоат блока равна ширине текста в нем и от text align ничего не зависит. Можно сделать чтобы блок был фиксированной ширины, например занимал по ширине все поле и тогда текст будет прижиматься вправо.
Еще тут можно использовать position absolute + хитрую комбинацию right и margin-right чтобы вынести блок влево и прижать его к правой кроме поля. Но я не уверен, на одной ли высоте с текстом он будет.
> А что делать если мы решили что искусственный интеллект справляется лучше чем "работник"?
Сделаем класс class AI extends Employee и у него в методе getSalary() напишем return 0 (денег то он не просит).
>>443203
> считаю количество строк, делю их на желаемое количество строк на одной странице
ну так это всего 2 строки. Вообще альтернативный способ есть: можно создать объект для управления постраничной навигацией (Pagination). Ты при создании даешь ему число записей, число записей на одной странице, номер страницы, шаблон ссылки. а он рассчитывает число страниц, генерирует ссылки и все прочее.
> Я про то, что мне непонятно само слово.
Ну ок
> инлайн до добра не доводит.
Имеется в виду inline обработчик события, заданный с помощью аттрибута onXXX у тега.
> Юзай жикверя,
jQuery — библиотека для работы с DOM. Юзай= используй (use)
> вешай действие.
Назначь обработчик для события.
>>443237
А может ли быть такое что у тебя на компьютере несколько php.ini и ты включил расширение не в том файле? Увидеть исползуемый файл можно выведя phpinfo(), там написано где именно лежит php.ini
>>443240
Это не помогло потому что у тебя ширина флоат блока равна ширине текста в нем и от text align ничего не зависит. Можно сделать чтобы блок был фиксированной ширины, например занимал по ширине все поле и тогда текст будет прижиматься вправо.
Еще тут можно использовать position absolute + хитрую комбинацию right и margin-right чтобы вынести блок влево и прижать его к правой кроме поля. Но я не уверен, на одной ли высоте с текстом он будет.
Я еще поясню. Это задача для изучения ООП и недостаточно, чтобы она выводила правильный результат. Это вообще тут второстепенно. Надо, чтобы код соответствовал принципам ООП. Ты можешь спросить, какие именно принципы? Ну есть такая аббревиатура SOLID например:
https://ru.wikipedia.org/wiki/SOLID_(%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
Начинающему может быть трудно понять (тем более что в статье в википедии нет объяснений), но например такого что базовый класс знает какие у него будут наследники, не должно быть. Это противоречит принципу «открытости для расширения»: если у тебя прописано в коде ровно 4 профессии, мы не можем добывлять новые не переделывая весь код. А правильно написанный департамент не должен знать, сколько существует профессий, он просто принимает любые объекты унаследованные от Employee.
Также, не стоит заводить избытоные свойства вроде newSalary. Оно избыточное так как его всего можно посчитать из имеющихся данных, а если мы его храним то мы вынуждены как-то реализовать код для пересчета зарплаты при изменении ранга. В реальных программах у объекта может быть 20 свойств и если у тебя будут такие сложные зависимости, ты запутаешься в своем же коде в итоге. А я пытаюсь от этого предостеречь.
Значит скачал я архив с X-Sendfile.
Что то там сонфигах написал. Как определить установился ли модуль?
Ага, посмотрел в phpinfo.
apache2handler
Loaded Modules: mod_xsendfile.
Но при попытке закачать выдаёт 404 ошибку. Эта штука сильнее меня.
Тупой вопрос, смотри, ты писал:
>>443115
>Если есть несколько элементов с одним именем то в
>f.elements.name
>будет массив этих элементов
Какой тип переменных у этого массива? А то в яве для for each надо указывать тип.
Кстати, по поводу SOLID, нашел такую ссылку: http://blog.byndyu.ru/2009/10/solid.html — можешь почитать, если интересно, но возможно что-то будет сложно понять, так как это все же материал рассчитанный на более опытных программистов.
Вечером может или завтра. Куда спешить? Мы на одной странице с уважаемым Хаскелл тредом.
>>443370
Не сдавайся. Через var_dump() и die() выведи какой ты заголовок отдаешь и проверь что он правильный.
>>443372
Я про яваскрипт писал. Какая ява? Ты подо что код пишешь?
В JS нет типа, там правда есть прототипы. если быть точным там не массив, а HTMLFormControlsCollection.
Описано например тут https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormControlsCollection
Какой же я лошара, оказывается ничто не мешает применить стандартный required к радиобатону.
И сразу вопрос, вот у меня допустим есть Index.html где осуществляется ввод данных и передается дальше через форму в скрипт который выше и на выходе допустим я получаю массив трех числе, как передать этот массив другому скрипту который бы осуществлял бы создание страницы вывода данных на экран? Не лепить же это под скриптом обработчика.
http://pastebin.com/Wn3wRujb
Я еще больший лошара, чем думал - стандартный required не работает в IE, лол.
В принципе, проверок заполнения форм в инете много, но я пока не нашел ни одну, нормально работающую с радиобатонами.
> $this->rang = $rang;
> $this->newSolary = $this->calculateSolary( );
>Это нехороший код. Базовый класс ничего не знает о своих потомках и не должен обращаться к свойствам которых у него нету.
>То есть ты должен объявить свойства вроде rang у базового класса.
>Вот это вот свойство
> public $rang;
>не надо копипастить, нужно один раз его объявить на базовом классе.
Ты говорил что нельзя в абстрактном классе определять параметры, и вообще даже идоне мне об сказал >>442511
>Нет. Абстрактным может быть класс (это значит что нельзя создать объект такого класса) либо метод (это метод без тела, который обязаны реализовать наследники класса).
>Потому я тебе советую удалить это свойство newSolary и проблема исчезнет сама собой.
Я правильно понимаю, что тогда вычисленная зарплата будет храниться в $solary? Я немного запутался.
>Если тебе сложно сразу понять как надо сделать, давай ты напишешь что-то вроде схемы, какие классы, свойства и методы ты хочешь сделать, а я скажу правильно ли все или что-то надо исправить. Или можешь сразу код менять, если хочешь.
Я добавлю в класс конкретной профессией параметр держащий в себе название этой профессии. Далее, мне на ум приходит мысль о том, что можно не копипастить код, а иметь всего один класс Employee, и при его создании задавать все свойства (название профессии, начальная ставка, кофе, количество документов, ранг и является ли он лидером), точно также можно поступить и с департаментами . При таком подходе становиться необходимым сделать не слабый такой рефакторинг, а именно:
1. В классе конкретного департамента необходимо избавиться от параметров с количеством сотрудников, оставить лишь один параметр с массивом, который будет держать всех сотрудников, а добавлять их мы уже будем где-нибудь снаружи, как это и должно быть на самом деле.
>лучше сделать, чтобы создавался пустой департамент и в него поле этого можно было добавлять работников.
>лучше добавлять работников снаружи.
2. Подружить все это дело с методами расчетов\добавления сотрудника.
>Если тебе что-то неясно или у тебя есть своя точка зрения, напиши, обсудим.
Нет, по большему счету мне все ясно пока, за исключением пару вещей:
С новым подходом пропадает необходимость в абстрактных классах т.к. все можно сделать в одних и тех же классах (Employee и Department). Хотелось бы услышать что ты думаешь по этому поводу. Я лично думаю, что абстрактные классы не нужны здесь.
>в идеале при назначении нового босса старый должен переставать им быть
Пока не знаю как это сделать, но хочу это самостоятельно придумать, но это уже после. Так что попрошу тебя, мне пока не говорить об этом. =^_^=
> $this->rang = $rang;
> $this->newSolary = $this->calculateSolary( );
>Это нехороший код. Базовый класс ничего не знает о своих потомках и не должен обращаться к свойствам которых у него нету.
>То есть ты должен объявить свойства вроде rang у базового класса.
>Вот это вот свойство
> public $rang;
>не надо копипастить, нужно один раз его объявить на базовом классе.
Ты говорил что нельзя в абстрактном классе определять параметры, и вообще даже идоне мне об сказал >>442511
>Нет. Абстрактным может быть класс (это значит что нельзя создать объект такого класса) либо метод (это метод без тела, который обязаны реализовать наследники класса).
>Потому я тебе советую удалить это свойство newSolary и проблема исчезнет сама собой.
Я правильно понимаю, что тогда вычисленная зарплата будет храниться в $solary? Я немного запутался.
>Если тебе сложно сразу понять как надо сделать, давай ты напишешь что-то вроде схемы, какие классы, свойства и методы ты хочешь сделать, а я скажу правильно ли все или что-то надо исправить. Или можешь сразу код менять, если хочешь.
Я добавлю в класс конкретной профессией параметр держащий в себе название этой профессии. Далее, мне на ум приходит мысль о том, что можно не копипастить код, а иметь всего один класс Employee, и при его создании задавать все свойства (название профессии, начальная ставка, кофе, количество документов, ранг и является ли он лидером), точно также можно поступить и с департаментами . При таком подходе становиться необходимым сделать не слабый такой рефакторинг, а именно:
1. В классе конкретного департамента необходимо избавиться от параметров с количеством сотрудников, оставить лишь один параметр с массивом, который будет держать всех сотрудников, а добавлять их мы уже будем где-нибудь снаружи, как это и должно быть на самом деле.
>лучше сделать, чтобы создавался пустой департамент и в него поле этого можно было добавлять работников.
>лучше добавлять работников снаружи.
2. Подружить все это дело с методами расчетов\добавления сотрудника.
>Если тебе что-то неясно или у тебя есть своя точка зрения, напиши, обсудим.
Нет, по большему счету мне все ясно пока, за исключением пару вещей:
С новым подходом пропадает необходимость в абстрактных классах т.к. все можно сделать в одних и тех же классах (Employee и Department). Хотелось бы услышать что ты думаешь по этому поводу. Я лично думаю, что абстрактные классы не нужны здесь.
>в идеале при назначении нового босса старый должен переставать им быть
Пока не знаю как это сделать, но хочу это самостоятельно придумать, но это уже после. Так что попрошу тебя, мне пока не говорить об этом. =^_^=
посоны у меня почему-то на страничке два скролла, я все ксс файлы перелопатил, если ставлю оверфлоу hidden, то оба исчезают. как оставить один??
Вообще, мне кажется ты мыслишь в правильном направлении.
> Ты говорил что нельзя в абстрактном классе определять параметры,
Абстрактные нельзя. А обычные можно.
> Я правильно понимаю, что тогда вычисленная зарплата будет храниться в $solary? Я немного запутался.
куда ты ее положишь, там она и будет храниться. А зачем ее вообще хранить? Можно сразу например выводить на экран.
> Далее, мне на ум приходит мысль о том, что можно не копипастить код, а иметь всего один класс Employee
Копипастить код конечно плохая идея.
> С новым подходом пропадает необходимость в абстрактных классах т.к. все можно сделать в одних и тех же классах (Employee и Department). Хотелось бы услышать что ты думаешь по этому поводу. Я лично думаю, что абстрактные классы не нужны здесь.
Отдельные классы для профессий удобны тем что легко добавлять новые профессии. В принципе можно и одним классом но там у тебя будет такой некрасивый огромный свич:
switch ($position) {
case self::POSITION_ENGINEER: ...
...
>>443668
Зачем ты злоупотребляешь оерфлоу? Я бы вообще совтетовал удалить все эти свойства, они реально нужны в 1% случаев а в 99% нет.
>>443404
запилим скоро.
Вообще, мне кажется ты мыслишь в правильном направлении.
> Ты говорил что нельзя в абстрактном классе определять параметры,
Абстрактные нельзя. А обычные можно.
> Я правильно понимаю, что тогда вычисленная зарплата будет храниться в $solary? Я немного запутался.
куда ты ее положишь, там она и будет храниться. А зачем ее вообще хранить? Можно сразу например выводить на экран.
> Далее, мне на ум приходит мысль о том, что можно не копипастить код, а иметь всего один класс Employee
Копипастить код конечно плохая идея.
> С новым подходом пропадает необходимость в абстрактных классах т.к. все можно сделать в одних и тех же классах (Employee и Department). Хотелось бы услышать что ты думаешь по этому поводу. Я лично думаю, что абстрактные классы не нужны здесь.
Отдельные классы для профессий удобны тем что легко добавлять новые профессии. В принципе можно и одним классом но там у тебя будет такой некрасивый огромный свич:
switch ($position) {
case self::POSITION_ENGINEER: ...
...
>>443668
Зачем ты злоупотребляешь оерфлоу? Я бы вообще совтетовал удалить все эти свойства, они реально нужны в 1% случаев а в 99% нет.
>>443404
запилим скоро.
Если ты подключвешь второй скрипт через require то ничего делать не надо — он и так будет видеть переменные от первого скрипта.
Неудачное название getDmg. Обычно так называют функции которые ничего не меняют, а просто возвращают какое-то значение. А тут ровно наоборот — она не возвращает, а принимает урон.
> return 1; // вернет 1 если первый убил второго героя
Вместо комментариев надо использовать говорящие константы вроде Game::FIRST_HERO_WINS
Но вообще, конечно код стал намного аккуратнее, и по моему, чуть компактнее.
>>443474
на http://dkab.github.io/jasmine-tests/ проверял?
Там проваливается 2 проверки:
> начальное значение должно быть равно 0 по умолчанию
> шаг должнен быть 1 по умолчанию
То есть если start или step не переданы, для них должны ставиться значения по умолчанию. И например
sequence()() вернет 0, а
sequence(5)() вернет 5
>>443491
Попробуй сам написать например
>>443489
> sequence(start = 0, step = 1) {
Это конечно удобно, параметры по умолчанию, но это то ли ES6 то ли ES5 который не везде работает. Это полезно, его изучать, но попробуй решить эту задачу в рамках ES3.
Неудачное название getDmg. Обычно так называют функции которые ничего не меняют, а просто возвращают какое-то значение. А тут ровно наоборот — она не возвращает, а принимает урон.
> return 1; // вернет 1 если первый убил второго героя
Вместо комментариев надо использовать говорящие константы вроде Game::FIRST_HERO_WINS
Но вообще, конечно код стал намного аккуратнее, и по моему, чуть компактнее.
>>443474
на http://dkab.github.io/jasmine-tests/ проверял?
Там проваливается 2 проверки:
> начальное значение должно быть равно 0 по умолчанию
> шаг должнен быть 1 по умолчанию
То есть если start или step не переданы, для них должны ставиться значения по умолчанию. И например
sequence()() вернет 0, а
sequence(5)() вернет 5
>>443491
Попробуй сам написать например
>>443489
> sequence(start = 0, step = 1) {
Это конечно удобно, параметры по умолчанию, но это то ли ES6 то ли ES5 который не везде работает. Это полезно, его изучать, но попробуй решить эту задачу в рамках ES3.
>Попробуй сам написать например
Да я сделал уже, но только для радиобатонов и там надо жестко задавать число батонов, что коряво, как мне кажется.
http://ideone.com/52MFVU
Чертова сажа.
>Все зависит от компании. Куда-то возьмут с первой, куда-то потребуют минимум 3 решить.
Т.е. если я довольно быстро решил два задания, можно попробовать походить по собеседованиям, а что им говорить/писать? показывать гитхаб и говорить что я быстро учусь?
https://github.com/someApprentice/Vector-Com
>Отдельные классы для профессий удобны тем что легко добавлять новые профессии. В принципе можно и одним классом но там у тебя будет такой некрасивый огромный свич:
>
>switch ($position) {
>case self::POSITION_ENGINEER: ...
>...
Эм, все красивенько получилось - нету никаких огромных свичей ^_^
Анончики, нужна ваша помощь, есть код и есть неработающая его часть. Суть в том что желтый блок должен растягиваться, но в отличии от пхпдисайнджера локалхост растягивать её не хочет. Поясните нубу в чем дело?
Пробовал. Если выставить ширину то желтая часть залазит под футер, так что не вариант.
>phpDesigner
ну вроде как должно так работать, а у тебя есть идеи как это замутить по другому?
Во-первых, это не ответ. Во-вторых, в твоем примере ты задаешь одним и тем же блокам флоат и инлайн-блок. Зачем? Убери из сайдбаров инлайн блоки, задай левому бару и #контент флоат лефт, правому бару флоат райт. А потом выкинь эту странную софтину, который ты пользуешься, и скачай sublime/phpstorm
И у меня для тебя есть кое-что еще. Ты тут много со мной спорил, мол зачем писать универсальный код, если у нас есть конкретная задача. Действительно, разумное возражение. Давай тогда дополним условия задачи таким образом:
-----
.....
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
-----
Я тебе советую сделать это задание, так как оно поможет лучше разбираться в ООП-подходе. По моим прикидкам при правильном коде это потребует дописать строк 40-50, что на мой взгляд немного. Сразу предупрежу, что антикризисный код вроде «уволить 30% сотрудников» не должен быть в классе Департамент (так как бороться с кризисом задача руководства компании, а не департамента), но ты можешь написать в департаменте универсальные методы вроде «уволить указанных сотрудников» или «выбрать N% сотрудников определенного типа».
Также, тебе скорее всего понадобится метод клонирования компании, чтобы сделать несколько копий компании и принять в каждой из них нужные меры.
А пока замечания по коду на гитхабе:
> https://github.com/someApprentice/Vector-Com/blob/master/Classes/Department.php#L2
Не надо require писать в каждый класс, напиши его один раз в index.php и этого достаточно
> //Я помню, что ты был против этой переменной, но с ней просто будет проще удобней посчитать средние значение. Сделай замечание если что-то не так.
Получилась плоха функция, потому что непонятно, что вернет результат вызова calculateAvargeValue? Среднюю зарплату? Среднее потребление кофе? Упадет с ошибкой? Такого неоднозначного кода быть не должно. Ты должен либо сделать конкретные методы (посчитать среднюю зарплату, посчитать среднее потребление кофе и производство страниц), либо ни одного. По моему, проще не делать ни одного (так как среднее там считается сложением чисел по департаментам и делением на число департаментов).
> calculateDepartmentExpensesCoffeAndDocuemnt
Лучше сделать 3 метода, чтобы они возвращали конкретное число. Сам сравни:
echo $department->getTotalSalary( ); // просто и понятно
и
list ($totalSalary, $totalCofee, $totalPages) = $department->calculateDepartmentExpensesCoffeAndDocuemnt( );
echo $totalSalary; // неужели это удобнее, писать 2 строки вместо одной?
Там еще в новых версиях PHP можно стало писать
echo $department->calculateDepartmentExpensesCoffeAndDocuemnt( )[0];
но это очень плохой код так как непонятно что такое 0?
Потому я советую сделать 3 отдельных функции с нормальными именами. Я так понимаю, ты не хотел писать цикл 3 раза, но это не тот случай когда такая оптимизация оправдана.
> Я сомневюась в необхадимости этой функции, ведь можно зделать тоже самое снаружи класса:
Конечно создавать работников надо снаружи. Департамет только принимает их на работу, а не создает. И разумеется такой код никуда не годится:
$department->employees[] = new Employee(...);
гораздо лучше закрыть доступ к массиву снаружи через метод:
$department->addEmployee(new Employee ....);
Так код будет и понятнее и надежнее.
> https://github.com/someApprentice/Vector-Com/blob/master/Classes/Department.php#L22
Тут можно сразу написать return count ... без лишних переменных.
> я использую такое же имя переменной как и у свойства. Не приведт ли это к путанице?
Нет, так как переменная и свойство хранят одно и тоже, логично их назвать одинаково. Перепутать их не получится из-за приставки $this->
> https://github.com/someApprentice/Vector-Com/blob/master/autoload.php#L2
Твой вариант подходит, но ты знаешь что в php уже есть функция-автозагрузчик? Достаточно добавить папку Classes в include_path:
$path = explode(PATH_SEPARATOR, get_include_path( ));
$path[] = $classesDir;
set_include_path(implode(PATH_SEPARATOR, $path));
spl_autoload_register( ); // зарегистрирует встроенный автозагрузчик
Мануал: http://php.net/manual/ru/function.spl-autoload.php
И у меня для тебя есть кое-что еще. Ты тут много со мной спорил, мол зачем писать универсальный код, если у нас есть конкретная задача. Действительно, разумное возражение. Давай тогда дополним условия задачи таким образом:
-----
.....
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
-----
Я тебе советую сделать это задание, так как оно поможет лучше разбираться в ООП-подходе. По моим прикидкам при правильном коде это потребует дописать строк 40-50, что на мой взгляд немного. Сразу предупрежу, что антикризисный код вроде «уволить 30% сотрудников» не должен быть в классе Департамент (так как бороться с кризисом задача руководства компании, а не департамента), но ты можешь написать в департаменте универсальные методы вроде «уволить указанных сотрудников» или «выбрать N% сотрудников определенного типа».
Также, тебе скорее всего понадобится метод клонирования компании, чтобы сделать несколько копий компании и принять в каждой из них нужные меры.
А пока замечания по коду на гитхабе:
> https://github.com/someApprentice/Vector-Com/blob/master/Classes/Department.php#L2
Не надо require писать в каждый класс, напиши его один раз в index.php и этого достаточно
> //Я помню, что ты был против этой переменной, но с ней просто будет проще удобней посчитать средние значение. Сделай замечание если что-то не так.
Получилась плоха функция, потому что непонятно, что вернет результат вызова calculateAvargeValue? Среднюю зарплату? Среднее потребление кофе? Упадет с ошибкой? Такого неоднозначного кода быть не должно. Ты должен либо сделать конкретные методы (посчитать среднюю зарплату, посчитать среднее потребление кофе и производство страниц), либо ни одного. По моему, проще не делать ни одного (так как среднее там считается сложением чисел по департаментам и делением на число департаментов).
> calculateDepartmentExpensesCoffeAndDocuemnt
Лучше сделать 3 метода, чтобы они возвращали конкретное число. Сам сравни:
echo $department->getTotalSalary( ); // просто и понятно
и
list ($totalSalary, $totalCofee, $totalPages) = $department->calculateDepartmentExpensesCoffeAndDocuemnt( );
echo $totalSalary; // неужели это удобнее, писать 2 строки вместо одной?
Там еще в новых версиях PHP можно стало писать
echo $department->calculateDepartmentExpensesCoffeAndDocuemnt( )[0];
но это очень плохой код так как непонятно что такое 0?
Потому я советую сделать 3 отдельных функции с нормальными именами. Я так понимаю, ты не хотел писать цикл 3 раза, но это не тот случай когда такая оптимизация оправдана.
> Я сомневюась в необхадимости этой функции, ведь можно зделать тоже самое снаружи класса:
Конечно создавать работников надо снаружи. Департамет только принимает их на работу, а не создает. И разумеется такой код никуда не годится:
$department->employees[] = new Employee(...);
гораздо лучше закрыть доступ к массиву снаружи через метод:
$department->addEmployee(new Employee ....);
Так код будет и понятнее и надежнее.
> https://github.com/someApprentice/Vector-Com/blob/master/Classes/Department.php#L22
Тут можно сразу написать return count ... без лишних переменных.
> я использую такое же имя переменной как и у свойства. Не приведт ли это к путанице?
Нет, так как переменная и свойство хранят одно и тоже, логично их назвать одинаково. Перепутать их не получится из-за приставки $this->
> https://github.com/someApprentice/Vector-Com/blob/master/autoload.php#L2
Твой вариант подходит, но ты знаешь что в php уже есть функция-автозагрузчик? Достаточно добавить папку Classes в include_path:
$path = explode(PATH_SEPARATOR, get_include_path( ));
$path[] = $classesDir;
set_include_path(implode(PATH_SEPARATOR, $path));
spl_autoload_register( ); // зарегистрирует встроенный автозагрузчик
Мануал: http://php.net/manual/ru/function.spl-autoload.php
Мне нужен резиновый блок посередине, а описанный тобой способ я и сам применял и как-то проблема совсем не решилась.
Да блять.
Спасибки, но уже сам нашел решение. Теперь надо решить задачу с прибиванием футера к низу странички
>А где код который напечатает таблицу?
Сейчас напишу. Хотел чтобы ты проверил сначала, вдруг что-то не правило будет. А то так выведу таблицу как надо, а код будет неправильным. Обидно будет.
>>444020
Я спорю потому что не понимаю твоего подхода. Универсальность понятие относительное, и в конечном итоге гонка за ней приведет в тупик. С другой стороны, решение конкретной задачи экономит силы на том что не нужно придумывать все возможные нюансы. Твоя задача должна дать понимание о том как использовать ООП. Согласись, что я на практике почти решил её - она бы справилась с выводом таблицы, но на деле задача оказалось не универсальной, не смотря на то что у задачи были другие конкретные цели. И поэтому я не понимаю: почему от меня требуется универсальный код, если условия задачи сами по себе не универсальны.
Я не хочу жаловаться, так как ты уже бесконечно много делаешь для меня и для всех, и вообще в целом. Меня просто демотивирует это непонимание.
Надеюсь на твое понимание.
>Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
=__________________________________________________________________=
Может ты сразу дашь задачу написать ИИ?
>$department->addEmployee(new Employee ....);
Не совсем понял как это делается
[code]
class Department {
...
public function addEmployee($employee) {
$this->employee[] = $employee;
}
}
...
$department->addEmployee(newEmployee(...));
[/code]
Верно?
> $manager->multiple(13,1),
Это не очень удачная идея, делать одного менеджера с зарплатой как у 13. Надо делать 13 объектов-менеджеров. Иначе, посмотри вот это дополнение к задаче: >>444020 — как ты будешь такое делать?
То есть удобнее и проще и правильнее сделать что один менеджер = 1 объект, 13 менеджеров = 13 объектов.
> $total+=$employee[3];
Это тоже плохая идея. Зачем хранить массив (в котром непонятно что значат ключи 0, 1, 2, 3) когда можно в Департаменте хранить массив объектов-сотрудников.
> public function rank($rank)
Функции надо называть осмысленно, в стиле сделайЧтоТо,например getIncomeForRank(). Это же отноcится и к multiple.
Добавлять сотрудников в департемент лучше через метод вроде
$dep->addEmployee($employee)
или
$dep->addEmployees(array($e1, $e2, $e3));
> \t\treturn $total = [$inc,$cof,$pap,$quan];
Не объединяй в одну строчку присваивание переменной значения и return. Пиши в 2 строки. Хотя тут можно вообще без переменной total обойтись и сразу возвращать массив.
> for($i = 0; $i < $length - $cl; $i++){
>\t\t\t$text = " ".$text;
Есть str_repeat, цикл не нужен
Не выводится среднее по департаментам и «всего».
Ну и чтобы ты лучше понял принципы и преимущества ООП (и чтобы заставить тебя сделать код правильным), сделай дополнительно задание отсюда: >>444020 про антикризисные меры.
> $manager->multiple(13,1),
Это не очень удачная идея, делать одного менеджера с зарплатой как у 13. Надо делать 13 объектов-менеджеров. Иначе, посмотри вот это дополнение к задаче: >>444020 — как ты будешь такое делать?
То есть удобнее и проще и правильнее сделать что один менеджер = 1 объект, 13 менеджеров = 13 объектов.
> $total+=$employee[3];
Это тоже плохая идея. Зачем хранить массив (в котром непонятно что значат ключи 0, 1, 2, 3) когда можно в Департаменте хранить массив объектов-сотрудников.
> public function rank($rank)
Функции надо называть осмысленно, в стиле сделайЧтоТо,например getIncomeForRank(). Это же отноcится и к multiple.
Добавлять сотрудников в департемент лучше через метод вроде
$dep->addEmployee($employee)
или
$dep->addEmployees(array($e1, $e2, $e3));
> \t\treturn $total = [$inc,$cof,$pap,$quan];
Не объединяй в одну строчку присваивание переменной значения и return. Пиши в 2 строки. Хотя тут можно вообще без переменной total обойтись и сразу возвращать массив.
> for($i = 0; $i < $length - $cl; $i++){
>\t\t\t$text = " ".$text;
Есть str_repeat, цикл не нужен
Не выводится среднее по департаментам и «всего».
Ну и чтобы ты лучше понял принципы и преимущества ООП (и чтобы заставить тебя сделать код правильным), сделай дополнительно задание отсюда: >>444020 про антикризисные меры.
Для inline-block нельзя задать ширину в стиле «100% - 200px» потому он тут не годится для реализации колонок. Годится например float для колонок + обычный блок с margin-left и right для средней части. Почитай это например: http://softwaremaniacs.org/blog/2005/12/01/css-layout-float/
Ну и высоту ты зря фиксированную задаешь, это неудобно.
Насчет прибитого к низу футера, делается отнсительно просто. Обертываешь все в wrapper, ставишь ему min-height 100% (чтобы это заработало, надо на body/html разумеется поставить height 100%), а под wrapper ставишь футер и делаешь ему margin-top: -100px где 100px это высота футера. Это древний способ, может сейчас что получше придумали, но я не уверен.
Также можно попытаться сделать таблицу из 2 ячеек (за счет display: table) но там много подвохов.
Также, у нас есть хорошие задачи для изучения CSS и способов позиционирования элементов (в ОП посте), советую их решить если чувствуешь что есть проблемы в знаниях. А я проверю и дам советы.
Я не против того, что ты сомневаешься в чем-то или споришь. Но я все же должен объяснить тебе суть ООП, потому сделай дополнительное задание про антикризисные меры. С ним тебе придется чуть переделать свой код и сделать его более универсальным. Тебе надо предусмотреть изменение рангов, смену руководителя департамента, изменение базовой ставки.
> И поэтому я не понимаю: почему от меня требуется универсальный код, если условия задачи сами по себе не универсальны.
Я придумал дополнительное задание, чтобы гнаться не за абстрактной целью, а за конкретной.
> Меня просто демотивирует это непонимание.
Есть что-то вроде общепринятого подхода. Ну например если я вижу у работника свойство rank (тем более публично доступное) я ожидаю, что его можно менять (и получить при этом новую величину зарплаты). Логично? Зачем иначе делать это свойство общедоступным?
Если я вижу у департамента руководителя, я ожидаю что его можно поменять. А это сделать нельзя. Неудобно. Чтобы приучить тебя делать чуть более универсальные и соответствующие ожиданиям классы, я придумал дополнительное задание.
>>444060
Процитированная строчка вообще-то из учебника. А дальше небольшое дополнение. В чем проблема его решить? По моему так оно решается элементарно:
Делаем 3 клона компании. В первом увольняем инженеров, во втором повышаем аналитиков, в третьем повышаем ранг менеджерам. После чего для каждой компании выводим таблицу (функция вывода ведь у тебя уже есть?)
Соответственно это надо строк 30-50 дописать. Совсем немного, согласись? Если твой код удобный и универсальный он легко позволит это сделать.
Какой ИИ? Это простая задача на проверку понимания ООП. Аналогичную или более сложную задачу могут дать в качестве тестового задания джуниору например (пруф http://www.cyberforum.ru/attachments/490610d1424108546 — кстати сейчас они из задачи на сайте убрали требования к ООП, видимо мало кто справился: http://job.lightsoft.ru/tech/testYourself )
Насчет клонов: в php есть оператор clone для того чтобы склонировать объект (обрати внимание, если ты клонируешь департамент, работники не клонируются по умолчанию: новый департамент будет хранить ссылки на тех же работников. То есть клонирование у нас неглубокое и клонирует только один объект, а не его содержимое. Ты должен явно написать метод клонирующий массив работников).
Вот мануал: http://php.net/manual/ru/language.oop5.cloning.php
Клонирование поможет сделать тебе несколько копий компании чтобы на каждой проверить ту или иную антикризисную меру.
Когда ты пишешь
$a = new X;
$b = $a;
клонирования не произойдет. $b и $a будут указывать на один и тот же объект: http://php.net/manual/ru/language.oop5.references.php
Также, советую тебе сделать в департаметне метод вида «выбрать N% работников нижних или верхних рангов определенного типа». C ним тебе легко будет выбрать работников и сделать с ними нужные изменения.
Ну и не забудь предумотреть метод для увольнения и метод для смены руководителя.
Спасибо, ОП!!!
Все няшно так встало и запустилось почти с первого раза. Красота!
https://github.com/someApprentice/Vector-Com
Спасибо что научил меня таким вот фокусам: <?=$variable;?>
С Sublime Text я себя чувствую джедаем кода прям!!! Ну хотя бы не джедаем, но как минимум подаваном точно!
Дальше буду думать над следующем заданием что ты мне дал.
>>444020
>Получилась плоха функция, потому что непонятно, что вернет результат вызова calculateAvargeValue? Среднюю зарплату? Среднее потребление кофе? Упадет с ошибкой? Такого неоднозначного кода быть не должно. Ты должен либо сделать конкретные методы (посчитать среднюю зарплату, посчитать среднее потребление кофе и производство страниц), либо ни одного. По моему, проще не делать ни одного (так как среднее там считается сложением чисел по департаментам и делением на число департаментов).
Не могу понять что не так с функцией. У тебя в задаче есть пункт: Посчитать средний расход тугриков на одну страницу.
Я её немного переделал, но принципиальной разницы не увидел. Тебе название функции не нравиться?
>Твой вариант подходит, но ты знаешь что в php уже есть функция-автозагрузчик? Достаточно добавить папку Classes в include_path:
Совсем не понял как этим пользоваться, но тут я уже сам ленюсь изучить. Я обязательно с этим разберусь самостоятельно, только чуть позже, потому что судя по всему это тоже какой-то крутой джедайский фокус.
> Я её немного переделал, но принципиальной разницы не увидел. Тебе название функции не нравиться?
Мне не понравилось использование массива expenses и такой код:
> $avargeValue = $this->expenses[0] / $this->expenses[2];
Так как массив может быть пуст, и вообще непонятно что он содержит. Раз ты убрал этот массив то претензий больше нет (хотя функцию я бы переименовал в getPagesPerTugrik()).
> Совсем не понял как этим пользоваться, но тут я уже сам ленюсь изучить. Я обязательно с этим разберусь самостоятельно, только чуть позже, потому что судя по всему это тоже какой-то крутой джедайский фокус.
Может оно тебе и не понадобится. Если будешь делать задание на регистрацию студентов, я посоветую использовать композер и там не нужен автозагрузчик.
> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
/ в конце тега ставится в XML, XHTML но не в HTML. Ну и в html5 испльзуют более короткую форму: http://htmlbook.ru/html/meta/charset
Тут длинные строки: https://github.com/someApprentice/Vector-Com/blob/master/index.php#L14 — разбивай их на короткие длиной не более 80-90 символов
Надо выводить среднее и сумму по департаментам.
Ну и ждем от тебя антикризисных сценариев.
>Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
Здесь в класс Депортамента я добавлю метод подсчета количества сотрудников определенного типа. Далее, я создам класс Кризис в котором буду находить сотрудников которых необходимо уволить, и с помощью нового метода в Депортаменте увольнять их.
Единственное что я не могу понять это как проверить всех сотрудников в каждом департаменте? Есть идея создать класс который будет хранить в массиве каждого сотрудника и вызываться каждый раз при создании нового сотрудника, но я сомниваюсь в её правильности.
у тебя данные не правильные выводятся в таблице в колонках по з/п и кофе. И нет итоговых данных.
Вы видите копию треда, сохраненную 11 марта 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.