Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%

<<< Формат JSON || JavaScript поиск по странице >>>

Корзина для интернет магазина php

02.03.2012
Корзина для интернет магазина php

Здравствуйте уважаемые читатели блога LifeExample, сегодня мы продолжим создавать интернет магазин с помощью PHP и реализуем еще несколько его модулей собственными руками. В прошлой части урока мы реализовали такие компоненты как каталог, карточка товара, и ЧПУ, а также сделали задел для системы наполнения каталога. Сегодня мы будем заниматься разработкой маленькой корзины для интернет магазина.

Предыдущие уроки:

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

Еще хочу заметить, весь код, который я представляю, не претендует на 100% правильность и в ваших силах найти в нем ошибки и оптимизировать, так как вы считаете нужным. Целью данного проекта является не дать вам готовую «болванку» интернет магазина, а научить всех желающих мыслить и самостоятельно разрабатывать PHP программы. Теперь давайте перейдем к процессу разработки нашей системы.

Предлагаю сразу скачать материалы по данному уроку, для наглядности наших дальнейших действий.

Листинг урока №3 ( Скачали: 9682 чел. ) 

Приступим. Какой же интернет магазин без корзины, в которую можно положить товар? Правильно, таких магазинов не существует, поэтому сейчас мы разработаем скрипт для маленькой корзины.

Маленькая корзина для интернет магазина

Под термином маленькая корзина, я понимаю тот интерфейс представления отложенных для покупки товаров, который, как правило, размещается в шапке сайта.

Маленькая корзина для интернет магазина

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

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

Существует несколько способов решения данной задачи:

  1. Хранить содержимое корзины для каждого зарегистрированного пользователя в БД
  2. Хранить содержимое корзины любого пользователя в Cookies браузера

В большинстве случаев второй вариант подходит лучше первого, поэтому мы его и разработаем. Т.е. в итоге у нас корзина должна работать в связке session + cookies

Приступим, отрываем header.php и вставляем в верстку вывод нашей корзины:

1
2
3
4
5
<div class="smalcart">
    <strong>Товаров в корзине:</strong><?=$smal_cart['cart_count']?> шт.
     <br/><strong>На сумму:</strong><?=$smal_cart['cart_price']?> руб.   
    <br/><a href=''>Оформить заказ</a>
</div>

Здесь у нас фигурирует вызов содержимого массива $smal_cart , который будет доступен в шаблоне после дальнейших действий.
Для удобного восприятия добавим в style.css стили для корзины:

1
2
3
4
5
6
7
8
9
10
11
12
#header .smalcart{
    float:right;   
    height:55px;
    padding: 10px;
    padding-left: 15px;
    margin: 10px;
    border: 1px solid gray;
    border-radius: 10px;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;  
    background: #E6DEEA;
}

Можете посмотреть на то, как изменился внешний вид сайта. Теперь давайте углубимся в структуру системы и начнем создавать нужные файлы.

Так как компонент маленькая корзина для интернет магазина не является отдельной страницей, то контроллера для нее мы создавать не будем, внешнее представление у нас уже есть в общем шаблоне, поэтому и отдельного views она тоже иметь не будет, а вот model все-таки придется сделать.

В папке \application\models\ создадим файл cart.php с таким содержанием:

1
2
3
4
5
6
7
8
9
10
11
12
class Application_Models_Cart
  {  
    function addToCart($id, $count=1)
    {        
     $_SESSION['cart'][$id]=$_SESSION['cart'][$id]+$count;     
    return true;
    }    
     
    function delFromCart($id, $count=1){}
     
    function clearCart(){}
  }

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

Все данные о продуктах из корзины, у нас будут храниться в массиве $_SESSION в виде ассоциативного массива, ключами которого будут ID продуктов, а значением – количество этих продуктов в корзине. Такой минимализм сыграет нам на руку при передаче этой информации в куки.

Теперь у нас есть модель Application_Models_Cart, и логично предположить, что она должна, откуда-то вызываться. Вызываться модель будет из контролера каталога. Почему каталога? Потому, что ссылки ‘В корзину‘ у нас расположены на странице каталога, завязанной на файлах view-controler-model относящихся к компоненту catalog. А еще и потому, что пока переходить на страницу большой корзины мы не будем. При нажатии на данные ссылки, мы должны оставаться на странице каталога, а информация в маленькой корзине должна изменяться.

Кстати о ссылках, ‘В корзину‘ , давайте сразу изменим значение атрибута href в представлении каталога

1
<a href="/catalog?in-cart-product-id=<?=$item["id"]?>">В корзину</a>

В результате получим ссылку вида

1
http://lifeexampleshop.ru/catalog?in-cart-product-id=1

При клике пользователя на данную ссылку, mvc-система передаст управление в application /controllers/catalog.php. Куда мы сейчас вставим нужный код обработчика данного события:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  class Application_Controllers_Catalog extends Lib_BaseController
  {
     function index()
    {
     if($_REQUEST['in-cart-product-id'])
     {
       $cart=new Application_Models_Cart;
       $cart->addToCart($_REQUEST['in-cart-product-id']);
       Lib_SmalCart::getInstance()->setCartData();
       header('Location: /catalog');
       exit;
     }
           
     $model=new Application_Models_Catalog;
     $Items = $model->getList();   
     $this->Items=$Items;      
     }
  }

Поясню, что тут происходит. Сначала проверяется, был ли щелчок по ссылке и передался ID продукта, который нужно добавить. Если GET параметр in-cart-product-id содержит ID , то управление передается в модель, которая функцией addToCart() , добавляет в корзину нужный продукт, либо только увеличивает его количество. Строка Lib_SmalCart::getInstance()->setCartData() , требует отдельного внимания, поэму я пока ее пропущу, представим, что ее просто нет. На этом этапе у нас есть вся информация о содержимом корзины интернет магазина, и хранится она в сессии. Поэтому мы можем спокойно вернуться на страницу каталога с помощью редиректа:

1
header('Location: /catalog');

Так как мы пока не знаем что такое AJAX и без перезагрузки страницы никак не сможем обойтись, мы просто возвращаемся на страницу каталога, для того чтобы увидеть изменения в корзине. (Об основах AJAX можно прочесть тут.)

На этом можно было бы остановиться, если бы не стояла задача сохранения информации при возвращении пользователя после закрытия браузера. Самое время вернуться к пропущенной строчке:

1
Lib_SmalCart::getInstance()->setCartData();

Стоит предупредить, что далее людям, мало разбирающимся в ООП, будет сложно понять код построчно, но в рамках общего смысла не будет ничего сложного. Что же происходит в этой строке:

  1. Lib_SmalCart – интерпретируется нашей системой как создание экземпляра класса SmalCart, расположенного в \lib\smalcart.php
  2. ::— получаем доступ к функциям класса
  3. Вызов любой функции данного класса должен проходить через функцию getInstance(), в задачи которой входит отсеять все возможные повторные попытки создания экземпляра этого класса. Такой метод называется Singleton.
  4. setCartData() – сериализует данные о корзине из сессии, и записывает их в cookie.

Для более четкого представления откройте файл \lib\smalcart.php в нем я постарался подробно описать суть каждой функции, поэтому особо комментировать нечего. Единственное, что нужно сказать это то, что вызов метода getCartData() этого класса, происходит и в файле function.php , который является еще одним отделителем логики от верстки и записывает в переменную $smal_cart всю необходимую для вывода информацию.

Помните первым шагом в этой статье мы в header.php вставили код:

1
2
3
4
5
<div class="smalcart">
    <strong>Товаров в корзине:</strong><?=$smal_cart['cart_count']?> шт.
     <br/><strong>На сумму:</strong><?=$smal_cart['cart_price']?> руб.   
    <br/><a href=''>Оформить заказ</a>
</div>

Так вот, теперь вы наверняка понимаете, откуда берется данный массив $smal_cart и можете заметить, что логическая цепочка обмена информации замкнулась.

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

Всем тем, кому требуются более тщательные объяснения, советую писать вопросы в комментариях, либо мне на e-mail.

Сегодня мы добавили немало кода, который требуется обмозговать и переварить, прежде чем преступать к следующим частям магазина. Надеюсь, что у вас не возникнет трудностей с пониманием данной статьи “Корзина для интернет магазина php”. Если вы еще не подписались на e-mail или rss рассылку, не стесняйтесь — подписывайтесь. Скачать листинг данного урока можно по ссылке:

Листинг урока №3 ( Скачали: 9682 чел. ) 


<<< Предыдущий урок | Следующий урок >>>

Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.

Нравится

Комментарии

  • Alexey

    Привет, Марк!
    Спасибо большое, я, вроде бы все понял из урока 3.
    Один вопрос: я слышал, что для быстродействия лучше использовать динамическую подгрузку классов, чем «require». Что вы по этому поводу думаете?

    • Mark

      Да , Алексей, динамическая подгрузка классов лучше чем подключение по «require», у нас она реализована с помощью функции __autoload() из конфигурационного файла. Require‘ ом мы подключаем файлы шаблона и файл функций.
      По части проверки включены куки или выключение, конечно в идеале она нужна, но т.к. это всего лишь урок мы без нее обойдемся. А вообще чтобы проверить их активность много труда не составит. Нужно проверить на существование массив $_COOKIE и соответственно обработать ответ.

  • Alexey

    А, и еще.
    Нужна, наверное, проверка активации куки у клиента.
    И если куки отключены — то при нажатии на кнопку «добавить в корзину»
    появляется сообщение «активируйте сначала кукис!».

  • Евгений
    1
    2
    3
    4
    5
    Warning: mysql_connect() [function.mysql-connect]: [2002] ... (trying to connect via tcp://mysql52.hoster.ru:3306) in Z:\home\test1.ru\www\config.php on line 25

    Warning: mysql_connect() [function.mysql-connect]:... in Z:\home\test1.ru\www\config.php on line 25

    Fatal error: Maximum execution time of 30 seconds exceeded in Z:\home\test1.ru\www\config.php on line 25
  • Mark

    Евгений эта ошибка у вас проявляется с Листингом №3 ?
    Попробуйте скачать 4-й урок, я перезалил архив с исправленными файлами, должно все работать.

  • Aleksandr

    Привет
    В скрипте, товар с страницы Каталог без проблем добавляется в корзину, а вот со страницы конкретного товара не добавляется в корзину, так задумано или у меня что-то не работает?

  • Mark

    Не то чтобы так задумано, я бы сказал — так не додумано. 🙂
    В следующей публикации доработаю.

  • Aleksandr

    Буду ждать, самостоятельно допилить не получилось.

  • Елена

    Привет, Марк. У меня такая проблема

    1
    2
    3
    Warning: Cannot modify header information - headers already sent by (output started at T:\home\proba\www\config.php:1) in T:\home\proba\www\lib\smalcart.php on line 19

    Warning: Cannot modify header information - headers already sent by (output started at T:\home\proba\www\config.php:1) in T:\home\proba\www\application\controllers\catalog.php on line 12
    • Ошибка говорит о том что в config.php происходит вывод информации на страницу, что сказывается на работе всей системы. Проверьте config.php, важно чтобы в нем не было никаких выводов echo, print , print_r, var_dump, и тому подобного. Также удалите последний символ ?> если он присутствует, и проследите чтобы в начале файла не было пробелов пере

  • Елена

    Спасибо за оперативность. Приятно удивилась. Файл проверила убрала символ ?>, закомментировала вывод echo, пробелов перед знаков препинания не нашла. Результат тот-же. Вот мой файл config.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?php
    //Error_Reporting(E_ALL & ~E_NOTICE);//не выводить предупреждения
    function __autoload ($class_name) //автоматическая загрузка кслассов
    {
    $path=str_replace("_", "/", strtolower($class_name));//разбивает имя класска получая из него путь

    if (file_exists($path.".php")) {

    include_once($path.".php");//подключает php файл по полученному пути
    }
    else{

    header("HTTP/1.0 404 Not Found");
    //echo "К сожалению такой страницы не существует. [".PATH_SITE.$path.".php ]";
    exit;
    }
    }
    //константы для подключения к базе данных

    define('PATH_SITE', $_SERVER['DOCUMENT_ROOT']); //сервер
    define('HOST', 'zharpizza'); //сервер
    define('USER', 'root'); //пользователь
    define('PASSWORD', '111111'); //пароль
    define('NAME_BD', 'LifeExampleShop');    //база
    $connect = mysql_connect(HOST, USER, PASSWORD)or die("Невозможно установить соединение c базой данных".mysql_error( ));
    mysql_select_db(NAME_BD, $connect) or die ("Ошибка обращения к базе ".mysql_error());
    mysql_query('SET names "utf8"'); //база устанавливаем кодировку данных в базе
    • В каком редакторе вы работаете?
      Посмотрите через notepad++ в какой кодировке файл?

      Если он в utf-8 witwout bom, то должно работать. Кстати echo в этом случае можно разкомментировать.

  • Елена

    Добрый день! Еще раз спасибо. Я работала в блокноте в UTF-8. Поставила notepad++ переделала кодировку на UTF-8 без bom. Причем сразу несколько файлов, на которые были ссылки в предупреждениях и корзина заработала.

  • Полина

    Всё установила, всё работает! Ура. Подскажите пожалуйста,как подключить,(присоединить) другие системы оплаты, такие как PayPal или же Robokassa или билинговые системы оплаты посредством SMS, так как у меня такой контент, который просто нужно скачивать с сайта, и никакой доставки, т.е. — заплатил — и скачивай. СПАСИБО

  • Заика

    Дошла до середины не понимаю двух вещей.
    1. Где находится папка В папке \application\models\ создадим файл cart.php с таким содержанием:
    2. Где находится эта ссылка7
    /////Кстати о ссылках, ‘В корзину‘ , давайте сразу изменим значение атрибута href в представлении каталога
    1
    <a href="/catalog?in-cart-product-id=»>В корзину
    В результате получим ссылку вида

    1
    _http://lifeexampleshop.ru/catalog?in-cart-product-id=1

  • Тимофей

    а что делать если браузер открывает этот файл в виде текста

  • Тимофей

    Надеюсь, это не я оставил последний коммент xDD

    ну если все-таки.. то, сам же себе отвечу.. =))

    В папке \application\models\ создадим файл cart.php с таким содержанием:
    — вот этот код нужно обрамить в теги

    вообще с xampp-ом тяжело очень работать, постоянно приходится быть внимательным с путями..

  • Тимофей

    Мне и остальным пользователям xampp
    посвящается!

    короче, братья!
    все траблы с отображением страниц кроются в путях файлов в каталоге application/views как правило.

    Обычно бывает достаточно убрать один слэш, чтобы, например путь http://localhost/es/catalog заработал по-человечески, а не радовал 404-й ошибкой object not found (в хроме так пишет)

  • Тимофей

    Настройка виртуального хоста решает проблемы путей.

    Единственный толковый гайд, который у меня заработал: (xampp-win32-1.7.7-VC9, windows 7 x64, сборка)

  • Тимофей

    вывод ошибок типа Notice: Undefined offset
    решается путем добавления строки

    1
    error_reporting(7)

    ;
    в index.php

    — остальное работает как по маслу, ы)

  • АН

    хорошо

  • Владимир

    Так ведь можно всё сделать чрез куки, для чего нужно сочетание сессии+сессии?

    • Сессии нужны, для того чтобы магазин работал даже у тех, у кого куки отключены.

  • Дмитр

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

  • Ирина

    Здравствуйте, Марк!
    Как по Вашему, что означает вот такая ошибка:
    Warning: Cannot modify header information — headers already sent by (output started at Z:\home\shop.ru\www\application\controllers\product.php:22) in Z:\home\shop.ru\www\lib\smalcart.php on line 15

    Warning: Cannot modify header information — headers already sent by (output started at Z:\home\shop.ru\www\application\controllers\product.php:22) in Z:\home\shop.ru\www\application\controllers\product.php on line 11

    • Такая ошибка говорит о том, что переl объявлением заголовков происходит вывод данных на страницу, что не есть правильно. Это может случиться от не правильной кодировки файлов. Если вы открывали файлы в обычном блокноте, то он мог сохранить их с битововй маской, т.е. дописать несколько символов перед содержимым файла. Проверьте чтобы все файлы находились в кодировке utf-8 без BOM/

  • Ирина

    Да! Спасибо за помощь. Протолкнула. Файл Z:\home\shop.ru\www\application\controllers\product.php заканчивался одной лишней пустой строкой, а header нужно отправлять до любого вывода текста в браузер, даже если этот текст- пробелы.

  • Майкл

    Марк, подскажите пожалуйста сакральное значение параметра ‘p’ в sql-запросе

    1
    $sql = "SELECT p.price FROM product p WHERE id='{$id}'";

    (файл lib/smalcart.php)
    .. всю голову изломал что это и зачем это..
    почему p.price? почему product p ?
    .. и кстати, для чего $id заключается в фигскобки?

    • Сакральное значение в следующем: p — это сокращение названия таблицы product, т.е. поля таблицы можно теперь вызывать двумя способами p.price или product.price
      фигурные скобки в данном примере , только для более четкого выделения, того что в строку внедрена переменная.

      Также используя фигурные скобки можно указать, например, константу.

  • nuklon

    Доброй ночи, Марк.
    пару дней назад писал вам сюда, но так и не дождался ответа, может комментарий не загрузился (здесь я его не вижу), поэтому напишу снова —
    делаю магазин обуви. У меня появилась проблема записи товаров в сессию (корзина), я не могу просто записывать товары в корзину как ключ=>значение (id=>count), т.к. есть еще параметр — размер обуви.
    Вот смотрите, добавил я, допустим, обувь (Модель-100, артикул = М100) 40-го размера, а следом и 41-го, и как же их записать в массив сессии? Как понимаете простой метод — id=>count здесь не катит, т.к. зависит еще и от размера, ведь я же должен знать, к какому размеру текущей модели относится данный count.
    Как решить такой момент?
    Мое решение:
    Создал таблицу cart (id, article, count, size, sid) sid — это хэш из 10-ти символов, уникальный для каждой сессии.
    Здесь я проверяю кроме id и артикул’а еще и размер, если все совпадает — увеличиваю count, иначе — добавляю новую строку.
    Данные из этой таблицы конечно удаляются после оформления заказа, и раз в сутки ч/з cron.
    Как считаете, нормальное ли решение? Что вы предложите?

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

    • nuklon, да интересное решение с хешем. Должно сработать.

  • Maks

    могу ли я разместить корзину на html странице?

  • Дмитрий

    Здравствуйте. Большое спасибо за ваши уроки. Столкнулся с такой же проблемой, как и nuklon. Может подскажете, в каком направлении двигаться, если кроме id нужно передать значение из выпадающего списка. Заранее благодарен.

  • Валентина

    работаю в macromedia dreamweaver. подскажите пожалуйста, у меня не получатся создать корзину вот по этим шагам, когда создаю файл cart.php он у меня не работает, помогите пожалуйста скоро сессия

  • Сергей

    Как реализовать что бы , было , что товар в наличие столько то или нет ?

    • Реализовать можно с помощью PHP ))) Добавляйте поле и сохраняйте в него количество.

  • artem

    У меня такая проблема возникла. я могу перейти по ссылке «оформить заказ» в маленькой корзине, только будучи авторизированным под администратора. другой пользователь, либо просто гость не может нажать на кнопку «оформить заказ» в маленькой корзине. в чем может заключаться ошибка?

  • Ярослав

    Здравствуйте, выдает такую ошибку, что делать?
    Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in C:\xampp\htdocs\shop\config.php on line 25

    getMenu(); ?>

    • qwerty

      Просто переведите текст, ключевое слово «deprecated»

  • Сергей

    Скажите… я так понимаю эту корзину можно прикрутить к любому каталогу. Например взять компонент каталога товаров для joomla или доски объявлений и прикрутить к нему эту корзину?

  • Иван

    Скачал листинг, попробовал запустить — получил ошибку:

    К сожалению такой страницы не существует. [C:/OpenServer/domains/cartswfcart.php ]

    Я делаю что то не так или же что то не так с самими файлами?

  • vg911

    Доброго времени суток! Подскажите, пожалуйста, человеку, далекому от программирования. У нас интернет-магазин мебели. Ранее сайтом занималась фирма, которая, увы, напортачила с корзиной. Ошибка заключается в следующем: «В окошке для изменения количества, изменяя 1 на нужное количество товара и далее при нажатии кнопки «В Корзину», товар уже не добавляется. Если значение 1 не менять, товар добавляется.» Нам никто не может помочь. При просмотре кода страницы нашла кусок, относящийся к корзине. Посмотрите, пожалуйста, где ошибка. Заранее спасибо большое.

    <!— —>

    В корзину

    <!— —>

  • Алла

    Здравствуйте!У меня вопрос по синтаксису.Я стараюсь не загружать каждый урок отдельно, а дописывать недостающие команды.В файл application/controllers/catalog он был вида

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
    //контролер обрабатывает данные каталога
      class Application_Controllers_Catalog extends Lib_BaseController
      {
         function index()
         {
             $model=new Application_Models_Catalog;
             $Items = $model->getList();   
             $this->Items=$Items;
           
         }
      }
    /*
      Автор: Авдеев Марк.
      e-mail: mark-avdeev@mail.ru
      blog: lifeexample.ru
    */
    ?>

    я просто добавила строку

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
             if($_REQUEST['in-cart-product-id'])
                {
                    $cart=new Application_Models_Cart;
                    $cart->addToCart($_REQUEST['in-cart-product-id']);
                    Lib_SmalCart::getInstance()->setCartData();
                    header('Location: /catalog');
                    exit;
                }

    система стала выдавать ошибку в последней строке.После того, как убрала закрывающий тег «?>» сайт заработал.Посмотрела Ваш пример, у Вас тоже закрывающий тег отсутствует.Вопрос: почему в данном конкретном случае он должен отсутствовать?

  • Оставить комментарий

    Подписаться на комментарии к этой статье по RSS

    Яндекс.Метрика