PHP - e-commerce project-1

1, Project introduction

1. Project development process

Product Manager: conduct requirements analysis and sort out requirements documents (product prototype documents) (requirements review)

UI Design: according to the requirements document, design each page and draw the design drawing

Front end: write front-end html code according to requirements documents and design drawings

Back end: technology selection, architecture design, database design, (development documents), development project function, self-test (unit test)

Test: write test cases and test them one by one. (divided into multiple wheels)

Online: the project is deployed to the online server

2. Main e-commerce modes

2.1 B2B - business to business

B2B (Business to Business) refers to the process that both the supplier and the demander of e-commerce transactions are businesses (or enterprises and companies). They use Internet technology or various business network platforms to complete business transactions. E-commerce is a specific and main form of modern B2B marketing.
  case: Alibaba,

2.2 C2C – individual to individual

C2C means Customer (Consumer) to Customer (Consumer), which means the e-commerce behavior between consumers. For example, a Consumer has a computer to trade through the network and sell it to another Consumer. This type of transaction is called C2C e-commerce.
  cases: used cars from Taobao, eBay and melon seeds

2.3 B2C - business to individual

B2C is the abbreviation of business to customer, and its Chinese abbreviation is "business to customer". "Business to customer" is a model of e-commerce, that is, the commercial retail model of selling products and services directly to consumers. This form of e-commerce is generally based on online retail, mainly with the help of the Internet to carry out online sales activities. B2C means that enterprises provide consumers with a new shopping environment - online store through the Internet, and consumers conduct online shopping, online payment and other consumption behaviors through the Internet.
  case: vipshop,

2.4 C2B – individual to business

C2B (Consumer to Business) is a new business model in the era of Internet economy. In the first mock exam, the Create Value, Consume Value, is changed by the mode.
   C2B mode is on the contrary to the well-known demand supply model (DSM). The real C2B should be produced by consumers first, and then by enterprises, that is, consumers first put forward demand, and then manufacturers organize production according to demand. Usually, consumers customize products and prices according to their own needs, or actively participate in product design, production and pricing. Products and prices highlight consumers' personalized needs, and manufacturers carry out customized production.
  case: Haier mall, Shangpin home accessories

2.5 O2O – online to offline

O2O, or Online To Offline, refers to combining offline business opportunities with the Internet to make the Internet a platform for offline transactions. This concept originated in the United States. The concept of O2O is very broad. It can involve both online and offline. It can be commonly referred to as O2O. Mainstream business management courses introduce and pay attention to O2O, a new business model.
  case: meituan, hungry

2.6 F2C - factory to individual

F2C refers to Factory to customer, that is, the e-commerce model from manufacturer to consumer.

2.7 B2C - Enterprise - Enterprise - individual

B2B2C is an e-commerce type of online shopping BUSINESS model. B is the abbreviation of BUSINESS and C is the abbreviation of CUSTOMER. The first B refers to the supplier of goods or services, the second B refers to the enterprise engaged in e-commerce, and C refers to consumers.
  the first BUSINESS is not limited to brand suppliers, film and television production companies and book publishers. Any commodity supplier or service supplier can become the first BUSINESS; Second, B is a B2B2C e-commerce enterprise, which integrates goods, services and consumer terminals at the same time through unified operation and management. It is a bridge between suppliers and consumers, provides high-quality services for suppliers and consumers, and is an Internet e-commerce service provider. C represents consumers who shop on the unified e-commerce platform built in the second B.
   B2B2C comes from the evolution and improvement of the current B2B and B2C mode. It perfectly combines B2C and C2C, and constructs its own logistics supply chain system through B2B2C e-commerce enterprises to provide unified services.
  case: Jingdong Mall and tmall mall

3. Pinyougou mall

Pinyougou e-commerce platform belongs to B2B2C e-commerce, which is similar to, tmall and other operation modes. Merchants can apply to open stores on the platform. After the operator passes the review, it has an independent merchant background. The system background includes operator background and merchant background. ThinkPHP framework + Vue.js front and rear end separation solution is used.

The front desk of pinyougou consists of home page system, merchant home page, commodity detail page, shopping cart system, order system, payment system, member system, comment system, commodity search, second kill, user center and other systems. Pinyougou uses ThinkPHP5 framework + Vue.js as the main framework to explain various solutions in actual development in detail.

4. Technical highlights

VueJS + Bootstrap is fully adopted as the front-end framework, and the front-end architecture is integrated with the idea of hierarchical design.

Use ThinkPHP5 as the back-end framework.

Integrate CORS cross domain technology.

The e-commerce mode adopts B2B2C mode, which is divided into three parts: business background, operator background and website foreground.

No refresh method (Ajax) is adopted for uploading pictures from the front end

The SMS interface of aggregation platform is used to send SMS.

Shopping cart solution using Cookie+Mysql.

Use the third party payment solution (Alipay).

Introduce the concepts of SPU and SKU.

Using a third-party login solution

2, System design

1. Data sheet design

Table nameremarks
pyg_adminBackground administrator table
pyg_roleBackground role table
pyg_authBackground permission table
pyg_categoryCommodity classification table
pyg_brandList of commodity brands
pyg_goodsCommodity list (SPU list)
pyg_goods_imagesProduct album list
pyg_attributeProduct attribute table
pyg_specList of commodity specifications and names
pyg_spec_valueCommodity specification value table
pyg_spec_goodsSpecification commodity list (SKU list)
pyg_cartShopping cart table
pyg_orderOrder form
pyg_order_goodsOrder item table
pyg_pay_logPayment record form
pyg_userForeground user table
pyg_typeCommodity model table
pyg_addressReceiving address table

2. Module design

Module namepurpose
Background front end projectThe front-end part of the background management system is in the front-end and back-end separation mode
Background interface moduleBackground management system interface, front and rear end separation mode
Foreground moduleForeground system, mvc mode
Common moduleIt mainly stores public model classes
Mobile terminal moduleMobile terminal h5, foreground system, extracurricular content

3, Project construction

1. Install and deploy tp framework

1.1 installation of TP5.0 frame

Method 1: download the framework compressed package from the official website and decompress it.

Mode 2: install through composer

In the working directory (the directory where the code is written, such as phpStudy/WWW directory), execute the following command

php composer.phar  create-project topthink/think pyg 5.0.*

1.2 configuring virtual sites

① Configure through phpStudy's "site domain name management" or directly modify apache's virtual host configuration file,
Point the site domain name to the public directory under the project directory

Main domain name: is mainly used to access the front desk

Subdomain name: is specially used to access the background interface

② Domain name resolution, modify the hosts file

Add domain name resolution as follows:

③ Restart apache and access the configured virtual site in the browser

The following interfaces can be opened for both domain names, indicating that the framework is successfully installed and the virtual site is successfully configured.

apache configuration reference (do not copy):

<VirtualHost *:80>
    DocumentRoot "E:\phpStudy\WWW\tpshop\public"
  	<Directory "E:\phpStudy\WWW\tpshop\public">
      	Options FollowSymLinks ExecCGI
        AllowOverride All
        Order allow,deny
        Allow from all
        Require all granted

1.3 hide entry file

Load mod in the httpd.conf configuration file_ module

Change AllowOverride None of httpd.conf and virtual site configuration file to All

Modify the. htaccess file in the public directory as follows (add an English question mark after index.php?)

<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]

2. Module division

Back end project module:

Module nameexplainpurpose
adminBackground modulemvc mode, background management system, subsequent reference code
adminapiBackground interface moduleFront and back end separation mode, background management system interface, classroom content
homeForeground modulemvc mode, foreground system, classroom content
commonCommon moduleIt mainly stores public models and classroom content
mobileMobile terminal moduleMobile terminal h5, foreground system, extracurricular content

To create a project module:

On the command line, switch to the project directory (such as phpStudy/WWW/pyg), and execute the following commands respectively

php think build --module admin
php think build --module adminapi
php think build --module home
php think build --module common
php think build --module mobile

3. Routing configuration

Configure the domain name routing for the admin API background interface module

Modify the application/config.php code as follows:

Enable debugging mode: add app_ The debug configuration value is changed from false to true

'app_debug'      => true,

Turn on the domain name routing function: URL_ domain_ The deploy configuration value is changed from false to true

'url_domain_deploy'      => true,

Modify the application/route.php code as follows:

Modify the index method of the application/adminapi/controller/Index.php controller file

Browser access
Note: if no route is defined under the adminapi domain name, is equivalent to

4. Database configuration

4.1 import data sheet

create database pyg character set utf8 collate utf8_general_ci

Import data table (source sql path)

After refresh, the data table is as follows:

4.2 configuring database connection information

(see manual – database – connecting to database)

In the TP framework, the connection information of the database is set through the configuration file.

Modify application/database.php

Test: modify the index method of application/adminapi/controller/Index.php

Query data

If the data is queried and no error is reported, the database configuration is successful.

5. Build background front-end project

The background management system adopts the front and rear end separation mode.

Background front-end project (provide a complete set of code):

Unzip the project to a working directory (such as phpstudy / www / pyg Vue)

Modify the interface domain name in src/assets/js/myaxios.js to the background interface domain name configured in the above steps; For example

Switch to the project directory on the command line and execute the following commands respectively

npm install
npm run dev

Browser access http://localhost:8080

4, Interface basic controller class

The background interface module adminapi is used to provide interface services for front-end and back-end separation projects, involving cross domain issues.

1. Cross domain

1.1 processing options pre check request

In the case of cross domain, the client sends the options pre check request first, and the interface server needs to process the pre check request.

In the entry file public/index.php, add the following code:

//Processing cross domain pre check requests
    //Allowed source domain names
    header("Access-Control-Allow-Origin: *");
    //Allowed request header information
    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
    //Allowed request types
    header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');

1.2 processing cross domain requests

All background interfaces need cross domain processing.

Create interface basic controller class: under the project directory, execute the following command

php think make:controller adminapi/BaseApi --plain

The controller file is in application/adminapi/controller/BaseApi.php

Create initialization method_ initialize()

//Initialization method
public function _initialize()
    //Allowed source domain names
    header("Access-Control-Allow-Origin: *");
    //Allowed request header information
    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
    //Allowed request types
    header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');

2. Respond

The interface response data format is uniformly agreed as a json string containing code, msg and data fields.

In the BaseApi controller, the method of defining fast response data is as follows:

     * General response
     * @param int $code Error code
     * @param string $msg Error description
     * @param array $data Return data
    public function response($code=200, $msg='success', $data=[])
        $res = [
            'code' => $code,
            'msg' => $msg,
            'data' => $data
        //Choose one of the following two lines
        //echo json_encode($res, JSON_UNESCAPED_UNICODE);die;
     * Response on failure
     * @param string $msg Error description
     * @param int $code Error code
    public function fail($msg='fail',$code=500)
        return $this->response($code, $msg);

     * Respond on success
     * @param array $data Return data
     * @param int $code Error code
     * @param string $msg Error description
    public function ok($data=[], $code=200, $msg='success')
        return $this->response($code, $msg, $data);


Modify application/adminapi/controller/Index.php

Inherit the BaseApi controller class,

index method, test the fast response method of packaging

get request access in postman or browser

5, Token login authentication based on JWT

1. Introduction to JWT

JSON web token (JWT) is the most popular cross domain authentication solution.

2. Principle of JWT

The principle of JWT is that after the server authenticates, a JSON object is generated and sent back to the client, as shown below.

"user name": "admin",
"role": "Super administrator",
"Expiration time": "2019-07-13 00:00:00"

In the future, when the client communicates with the server, the JSON object will be sent back, and the server will only rely on this object to identify the user identity.
In order to prevent users from tampering with data, the server will add a signature when generating this object (see later).
The server no longer saves any session data, that is, the server becomes stateless, so it is easier to expand.

3. Data structure of JWT

The actual JWT is a very long string separated into three parts by dots (.). As follows:


The three parts of JWT are as follows.

  • Header
  • Payload
  • Signature

Write it in one line, which is what it looks like below.


3.1 Header

The Header part is a JSON object that describes the metadata of JWT, usually as follows.

 "alg": "HS256",
 "typ": "JWT"

In the above code, the alg attribute represents the signature algorithm, and the default is HMAC SHA256 (written as HS256); The typ attribute indicates the type of the token. JWT tokens are uniformly written as JWT.

Finally, convert the above JSON object into a string using the Base64URL algorithm (see later).

3.2 Payload

The Payload part is also a JSON object, which is used to store the actual data to be transferred. JWT specifies 7 official fields for selection.

iss (issuer)Issuer The issuer request entity can be the information of the user who initiated the request or the issuer of jwt
sub (Subject)themeSet the subject, similar to the subject when sending e-mail
aud (audience)audienceParty receiving jwt, receiver
exp (expire)Expiration timetoken expiration time, timestamp
nbf (not before)entry-into-force timeThe token cannot be used when the current time is before the nbf set time
iat (issued at)Time filed token creation time
jti (JWT ID)numberSet a unique identifier for the current token

In addition to official fields, you can also define private fields in this section. The following is an example.

"sub": "Nothing but handsome",
"name": "Zhang San",
"status": "1"

Note that JWT is not encrypted by default and can be read by anyone, so don't put secret information in this part.

The JSON object should also be converted into a string using the Base64URL algorithm.

3.3 Signature

The Signature part is the Signature of the first two parts to prevent data tampering.
First, you need to specify a secret, which is known only to the server and cannot be disclosed to the user. Then, use the signature algorithm specified in the Header (HMAC sha256 by default) to generate a signature according to the following formula.

base64UrlEncode(header) + "." +

After the Signature is calculated, the Header, Payload and Signature are spliced into a string. Each part is separated by a dot (.) and can be returned to the user.

3.4 Base64URL

As mentioned earlier, the Header and Payload serialization algorithm is Base64URL. This algorithm is basically similar to Base64 algorithm, but there are some small differences.

As a token, JWT may be placed in the URL on some occasions (such as Base64 has three strings +, / and =.
There is a special meaning in the URL, so it should be replaced: = omitted, + replaced with -, / replaced with. This is the Base64URL algorithm.

4. Use of JWT

The client receives the JWT returned by the server, which can be stored in cookies or localStorage.

After that, the client should bring this JWT every time it communicates with the server. You can send it automatically in a Cookie, but it can't cross domains. Therefore, it is better to put it in the Authorization field of the header information of the HTTP request.

Authorization: Bearer <token>

Another way is to put JWT in the data body of POST request when cross domain.

5. Several characteristics of JWT

(1)JWT is not encrypted by default, but it can also be encrypted. After generating the original Token, you can encrypt it again with the key.
(2) When JWT is not encrypted, secret data cannot be written to JWT.
(3)JWT can be used not only for authentication, but also for exchanging information. Using JWT effectively can reduce the number of times the server queries the database.
(4) The biggest disadvantage of JWT is that because the server does not save the session state, it is impossible to invalidate a token or change the permission of a token during use. That is, once the JWT is issued, it will remain valid until it expires, unless the server deploys additional logic.
(5)JWT itself contains authentication information. Once it is leaked, anyone can obtain all the permissions of the token. In order to reduce embezzlement, the validity period of JWT should be set relatively short. For some important permissions, users should be authenticated again.
(6) In order to reduce embezzlement, JWT should not use HTTP protocol for explicit transmission, but HTTPS protocol for transmission.

6. Function realization

6.1 JWT functional components

Installing JWT functional components using composer

php composer.phar require lcobucci/jwt 3.3

Encapsulate JWT tool classes (reference

namespace tools\jwt;

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;

 * Created by PhpStorm.
 * User: asus
 * Date: 2019/4/5
 * Time: 13:02
class Token
    private static $_config = [
        'audience' => ' ', / / recipient
        'id' => '3f2g57a92aa',//The unique identifier of the token. This is just a simple example
        'sign' => 'pinyougou',//Signature key
        'issuer' => ' ', / / issuer
        'expire' => 86400, //term of validity
    //Generate token
    public static function getToken($user_id){

        //Signature object
        $signer = new Sha256();
        //Get current timestamp
        $time = time();
        //Set issuer, receiver, unique id, issuing time, effective immediately, expiration time, user id and signature
        $token = (new Builder())->issuedBy(self::$_config['issuer'])
            ->identifiedBy(self::$_config['id'], true)
            ->expiresAt($time + self::$_config['expire'])
            ->with('user_id', $user_id)
            ->sign($signer, self::$_config['sign'])
        return (string)$token;

    //Get token token from request information
    public static function getRequestToken()
        if (empty($_SERVER['HTTP_AUTHORIZATION'])) {
            return false;

        $header = $_SERVER['HTTP_AUTHORIZATION'];
        $method = 'bearer';
        //Remove the possible bearer ID in the token
        return trim(str_ireplace($method, '', $header));

    //Obtain the user id from the token (including the verification of the token)
    public static function getUserId($token = null)
        $user_id = null;

        $token = empty($token)?self::getRequestToken():$token;

        if (!empty($token)) {
            //In order to log off the token, add the following if judgment code
            $delete_token = cache('delete_token') ?: [];
            if(in_array($token, $delete_token)){
                //token has been deleted (logout)
                return $user_id;
            $token = (new Parser())->parse((string) $token);
            //Validate token
            $data = new ValidationData();
            $data->setIssuer(self::$_config['issuer']);//Issuer of verification
            $data->setAudience(self::$_config['audience']);//Verified recipient
            $data->setId(self::$_config['id']);//Verify token ID

            if (!$token->validate($data)) {
                //token validation failed
                return $user_id;

            //Verify signature
            $signer = new Sha256();
            if (!$token->verify($signer, self::$_config['sign'])) {
                //Signature verification failed
                return $user_id;
            //Get user id from token
            $user_id = $token->getClaim('user_id');

        return $user_id;

Modify the public/.htaccess file and rewrite it through apache to process the Authorization field in the HTTP request

(no processing, no http_authorization field information is received in php)

    RewriteCond %{HTTP:Authorization} ^(.+)$
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Test: index method in application/adminapi/controller/Index.php

Statically call the getToken method of the encapsulated \ tools\jwt\Token class, pass a user id value, and generate a token

Statically call the getUserId method of the encapsulated \ tools\jwt\Token class, pass a token, and get the user id value

Browser access:

A token is generated, and the user id obtained according to the token is consistent with the user id passed when generating the token, indicating that the token class is encapsulated successfully.

6.2 verification code interface

The verification code interface is used to obtain the picture address and identification of the verification code when displaying the login page

Install the verification code function component (if it is the full version of the framework downloaded from the official website, it does not need to be installed)

php composer.phar  require topthink/think-captcha 1.*

Set the route. In application/route.php, the adminapi domain name routing part. The added code is as follows

//Verification code picture
Route::get('captcha/:id', "\\think\\captcha\\CaptchaController@index");//Need to access pictures
Route::get('captcha', 'adminapi/login/captcha');

Create Login controller: under the project directory, execute the following command

php think make:controller adminapi/Login --plain


Inherit BaseApi and create captcha method


namespace app\adminapi\controller;

use think\Controller;

class Login extends BaseApi
     * Get verification code picture address
    public function captcha()
        //Verification code identification
        $uniqid = uniqid(mt_rand(100000, 999999));
        //Return data verification code picture path and verification code identification
        $data = [
            'src' => captcha_src($uniqid),
            'uniqid' => $uniqid

Test: browser or postman access

The verification code can be customized according to actual needs: application/config.php

General processing (optional)

The verification code component stores the characters in the verification code in the session by default.

Considering that some clients (such as mobile app) generally do not use session (the request to display the verification code and the request to log in, and their session sessions are independent of each other).

The source code of the modifiable component is as follows:

In the entry method of vendor / topthink / think captcha / SRC / captcha.php

During subsequent verification, first fetch the corresponding session_id from the cache and set the session_id. see the login interface.

6.3 login interface

① Create an administrator model (note that the administrator table is pyg_admin, and the corresponding model name is Admin)

php think make:model common/Admin

② Set the route. In application/route.php, the adminapi domain name routing part. The added code is as follows

//Sign in
Route::post('login', 'adminapi/login/login');

③ Encapsulating cryptographic functions
Note: the initial administrator password in the background administrator table tpshop_admin needs to be encrypted and updated to the data table

Use a custom password encryption function:

Use the encryption function to encrypt and output a user-defined initial password.


Copy and modify the encrypted password to the passwod field of tpshop_admin table.
④ Login function

Create login method in application/adminapi/controller/Login.php

     * Login interface
    public function login()
        //Get input variable
        $param = input();
        $validate = $this->validate($param, [
            'username' => 'require',
            'password' => 'require',
            'code' => 'require',
            'uniqid' => 'require'
        if($validate !== true){
        //Take out the session_id from the cache and reset the session_id according to the verification code ID
        //Manual verification method is used for verification code verification
        if (!captcha_check($param['code'], $param['uniqid'])) {
            //Verification code error
            $this->fail('Verification code error');
        //Query the administrator user table according to the user name and password (encrypted password)
        $where = [
            'username' => $param['username'],
            'password' => encrypt_password($param['password'])
        $info = \app\common\model\Admin::where($where)->find();
            //Wrong user name or password
            $this->fail('Wrong user name or password');
        $data['token'] = \tools\jwt\Token::getToken($info->id);
        $data['user_id'] = $info->id;
        $data['username'] = $info->username;
        $data['nickname'] = $info->nickname;
        $data['email'] = $info->email;
        //Login succeeded

6.4 exit interface

① Set the route. In application/route.php, the adminapi domain name routing part. The added code is as follows

//sign out
Route::get('logout', 'adminapi/login/logout');

② Create logout method

Create the logout method in application/adminapi/controller/Login.php

 * Background exit interface
public function logout()
    //Clear the token and store the token to be cleared in the cache. When it is used again, it will read the cache for judgment
    $token = \Token::getRequestToken();
    $delete_token = cache('delete_token') ?: [];
    $delete_token[] = $token;
    cache('delete_token', $delete_token, 86400);

6.5 login detection

Except for login related interfaces, other interfaces can only be accessed after login.

Check in application/adminapi/controller/BaseApi.php.

① Set the list of detection methods not required

//Requests that do not require login detection
protected $no_login = ['login/login', 'login/captcha'];

② Test

 //Login detection
        //Gets the controller method name of the current request
        try {
            $path = strtolower($this->request->controller()) . '/' . $this->request->action();
            if (!in_array($path, $this->no_login)) {
                //Login detection is required
                $user_id = \tools\jwt\Token::getUserId();
                if (empty($user_id)) {
                    $this->fail('token Validation failed');
                //Put the obtained user id into the request information for subsequent use
                $this->request->get('user_id', $user_id);
                $this->request->post('user_id', $user_id);
        } catch (\Exception $e) {
            //token parsing failed
            $this->fail('token Parsing failed');

Test: inherit the index controller from the BaseApi and access it by the browser


Project construction and configuration, data table design, BaseApi basic controller class (cross domain processing, response method)

Verification code interface, login interface, exit interface and login detection function

Tags: PHP Javascript Front-end Vue.js

Posted on Mon, 29 Nov 2021 20:28:56 -0500 by Jasp182