分类 PHP 下的文章

安装包 (win10并开启虚拟化)

https://download.docker.com/win/stable/Docker%20for%20Windows%20Installer.exe

git 仓库

git@github.com:weiyixi/docker_study.git
目录说明
  1. nginx 站点配置在 ./docker-lnmp/nginx/site (修改后重启nginx容器生效)
  2. php-fpm 容器中/var/www/目录挂载本地docker-lnmp的上层目录(.env中 APPLICATION=../)
  3. 需要加扩展在对应得dockerfile 中修改

1.修改配置

env-example  复制为 .env
//window需要修改
DOCKER_SYNC_STRATEGY=unison
//php版本修改默认7.2
PHP_VERSION=72

2.基本操作

首先到docker-lnmp目录下

1.构建  docker-compose build  nginx php-fpm  redis  mysql 
2.开启  docker-compose up -d  nginx  redis  mysql 
3.关闭  docker-compose down
4.查看运行中容器  docker  ps
5.进入容器中   docker exec -it 对应的CONTAINER_ID  bash

3.扩展

1.已经定义了一批扩展可在 .env中开启 true开启 false 关闭
2.未定义的需要修改dockerfile安装
3.修改后需要重新build 开启才会生效

适用于对docker有一定了解的朋友,小白请先仔细阅读官方文档!
作为应用程序,我们通常需要依赖于多种外部服务,比如数据库、缓存服务等等。
Docker-compose就是在Docker容器的基础上,提供了统一的容器编排语言,可以让你更轻松的利用Docker构建你的应用环境。

docker-compose.yml文件语法语法

image 使用的镜像
build 指定Dockerfile构建
command 启动执行命令
links 链接其他容器    
ports 端口映射
expose 暴露端口
volumes 挂载路径
volumes_from 从容器挂载
environment 环境变量
  1. 编写dockerfile(自定义镜像)
  2. 编写docker-compose.yml(可以不依赖Dockerfile 使用官方镜像)

常用命令

构建容器 docker-compose up -d
查看容器 docker-compose ps
进入容器 docker exec -it 容器名 /bin/bash
关闭所有 docker-compose  down

php-fpm Dockerfile 示例 可以自定义扩展

FROM php:7.1-fpm-alpine

# apk
RUN apk --update add \
        autoconf \
        build-base \
        linux-headers \
        libaio-dev \
        zlib-dev \
        curl \
        git \
        subversion \
        freetype-dev \
        libjpeg-turbo-dev \
        libmcrypt-dev \
        libpng-dev \
        libtool \
        libbz2 \
        bzip2 \
        bzip2-dev \
        libstdc++ \
        libxslt-dev \
        openldap-dev \
        imagemagick-dev \
        make \
        unzip \
        wget \
        libmemcached-dev

# PHP Core Extensions
RUN docker-php-ext-install \
        bcmath \
        pdo_mysql \
        mysqli \
        pcntl \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd

# PECL Extensions
RUN pecl install redis-4.2.0 \
    && pecl install mongodb-1.5.3 \
    && pecl install memcached-3.1.3 \
    && pecl install swoole-4.3.1 \
    && docker-php-ext-enable redis mongodb memcached swoole

# Delete
RUN apk del build-base \
        linux-headers \
        libaio-dev \
    && rm -rf /var/cache/apk/* \
    && mkdir /data \
    && chmod -R 777 /data

VOLUME /var/www
WORKDIR /var/www

EXPOSE 9000
CMD ["php-fpm"]

docker-compose.yml示例

version: "3.0"
services:
  nginx:
    image: nginx:alpine
    ports: 
      - 80:80
      - 443:443
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ../:/var/www

  php-fpm:
    build: ./php-fpm
    ports:
        - 9000:9000
    volumes:
      - ./php-fpm/php.ini:/usr/local/etc/php/php.ini
      - ./php-fpm/www.conf:/usr/local/etc/php-fpm.d/www.conf
      - ../:/var/www

  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=123456

  redis:
    image: redis:5.0-alpine
    ports:
      - 6379:6379
    volumes:
      - ./redis/data:/data
      #- ./redis/redis.conf:/usr/local/etc/redis/redis.conf

  mongo:
    image: mongo
    ports: 
      - 27017:27017
    volumes:
      - ./mongo/data:/data/db
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: 123456

<?php

/**
 * 爬取 国外高校犯罪信息数据
 * Class SchoolSpider
 */
class SchoolSpider
{
    private $schoolName;
    //学校名检查api
    private $schoolApi = 'https://ope.ed.gov/campussafety/api/institution/names?filter=';
    //校区
    private $schoolSerachApi = 'https://ope.ed.gov/campussafety/api/institution/search';
    //数据  校区
    private $dataApi = 'https://ope.ed.gov/campussafety/api/campus/';
    //整个学校
    private $totalApi = 'https://ope.ed.gov/campussafety/api/institution/';
    //校区
    private $campisesData;
    //详情数据
    private $dataDetail;
    //详情数据
    public $error;

    public $result=[];

    public function __construct()
    {
        //请求时间不限
        set_time_limit(0);
    }

    public function spiderData($schoolName)
    {
        $this->schoolName = $schoolName;
        $this->result['school_name'] = $this->schoolName;
        if (!$this->checkName() || !$this->getCampises()) {
            return ['code' => -1, 'msg' => $this->error];
        }
        //总的数据
        $this->formatData($this->campisesData);
        //各个分校区数据
        $this->formatData($this->campisesData[0]['Campuses'],1);

        return ['code' => 0, 'msg' => $this->error,'data'=>$this->result];
    }


    /**
     * @name  数据解析
     * @param $campisesData 数据
     * @param $isCampise  是否是分校区数据
     */
    private function formatData($campisesData,$isCampise=false){

        foreach ($campisesData as $campise) {
            if($isCampise){
                //校区名
                $res = $this->getDetailCampuse($campise['UnitID']);
            }else{
                $res = $this->getDetail($campise['UnitID']);
            }

            if(!$res||isset($this->result[$campise['UnitID']])){
                continue;
            }
            $dataDetail = $this->dataDetail;
            //校名
            $this->result[$campise['UnitID']]['campuse'] = $campise['Name'];
            foreach ($dataDetail as $k => $data) {
                if ($k == 0)
                    continue;
                $this->result[$campise['UnitID']]['data'][] = empty($data) ? [] : array_column($data['Cells'], 'Html');
            }
        }
    }

    /**
     * 检查学校名
     * @return array
     */
    private function checkName()
    {
        $school = json_decode($this->httpRequest($this->schoolApi . urlencode($this->schoolName)), true);
        if (!isset($school[0]['Code']) || !$school[0]['Code']) {
            $this->error = '检查学校名 error';
            return false;
        }
        return true;
    }

    /**
     * 获取校区
     * @return array
     */
    private function getCampises()
    {
        $schoolSerachData = "{\"name\":\"" . $this->schoolName . "\",\"city\":\"\",\"state\":[],\"country\":[],\"countryNames\":[],\"institutionType\":[],\"institutionProgram\":[],\"campusLocation\":\"-1\",\"onlyResidentialCampuses\":false,\"enrollmentRange\":[],\"sort\":\"name\",\"sortDirection\":\"asc\",\"all\":false,\"pageNumber\":0,\"fromFavorites\":false}";
        //获取校区列表
        $campisesData = json_decode($this->httpRequest($this->schoolSerachApi, $schoolSerachData), true);

        if (!isset($campisesData['Results'][0]['Campuses']) || empty($campisesData['Results'][0]['Campuses'])) {
            $this->error = '获取校区 error';
            return false;
        }
        $this->campisesData = $campisesData['Results'];
        return true;
    }

    /**
     * @name 获取全部详情
     * @param $unitId
     * @return array
     */
    private function getDetail($unitId)
    {

        $dataDetail = json_decode($this->httpRequest($this->totalApi . $unitId), true);

        if (!isset($dataDetail['Groups'][0]['Screens'][0]['Rows']) || empty($dataDetail['Groups'][0]['Screens'][0]['Rows'])) {
            $this->error = '获取详情 error';
            return false;
        }
        $this->dataDetail = $dataDetail['Groups'][0]['Screens'][0]['Rows'];
        return true;
    }

    /**
     * @name 获取分校区详情
     * @param $unitId
     * @return array
     */
    private function getDetailCampuse($unitId)
    {

        $dataDetail = json_decode($this->httpRequest($this->dataApi . $unitId), true);

        if (!isset($dataDetail['Groups'][0]['Screens'][0]['Rows']) || empty($dataDetail['Groups'][0]['Screens'][0]['Rows'])) {
            $this->error = '获取详情 error';
            return false;
        }
        $this->dataDetail = $dataDetail['Groups'][0]['Screens'][0]['Rows'];
        return true;
    }

    /**
     * @name 请求方法
     * @param $url
     * @param $data
     * @return false|mixed|string
     */
    private function httpRequest($url, $data = '')
    {
        $curl = curl_init();
        $method = $data ? 'POST' : 'GET';
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS => $data,
            CURLOPT_HTTPHEADER => array(
                "Content-Type: application/json;charset=UTF-8",
                "Postman-Token: a30f51b0-cc09-4bfb-801e-830a931994f4",
                "cache-control: no-cache"
            ),
        ));

        $response = curl_exec($curl);
        $err = curl_error($curl);

        curl_close($curl);

        if ($err) {
            echo "cURL Error #:" . $err;
            return json_encode([]);
        } else {
            return strip_tags($response);
        }
    }
}

$a = new  SchoolSpider();
$r = $a->spiderData('Harvard University');
echo  json_encode($r);

<?php
$spider = new SpiderExample();
///question/267782048
$result = $spider->getData('https://www.zhihu.com/question/267782048/answer/330283932', [], $method = 'post');
var_dump($result);

/**
 * Class SpiderExample
 */
class SpiderExample
{

    private $cookie;

    /**
     * SpiderExample constructor.
     * @param string $cookieFile
     */
    public function __construct($cookieFile = './tmp')
    {
        header("Content-type: text/html; charset=utf-8");
        set_time_limit(0);
        //设置cookie文件
        $this->cookie = tempnam('./tmp', 'cookieSpiderExample' . date('Y-m-d'));
    }

    /**
     * 需要登录的先登录
     * @param $url
     * @param $postData
     * @param string $method
     * @return array|bool
     */
    public function login($url, $postData, $method = 'POST')
    {
        return $this->query(['url' => $url, 'data' => $postData], true, $method);
    }

    /**
     * 获取数据
     * @param $url
     * @param $postData
     * @param string $method
     * @return array|bool
     */

    public function getData($url, $postData, $method = 'POST')
    {
        return $this->query(['url' => $url, 'data' => $postData], false, $method);
    }

    /**
     * @param array postData
     * [
     *      'url'=>'',//链接
     *      'data'=>''//数据
     * ]
     * @param bool type 是否是登录请求
     * @param string method POST请求/get
     * @return array|bool
     */
    private function query($postData, $type = false, $method = 'POST')
    {
        $curl = curl_init();
        if ($type)
            $cookie_type = CURLOPT_COOKIEJAR;
        else
            $cookie_type = CURLOPT_COOKIEFILE;

        curl_setopt_array($curl, array(
            CURLOPT_URL => $postData['url'],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            $cookie_type => $this->cookie,
            CURLOPT_TIMEOUT => 120,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            //是否验证https
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSL_VERIFYPEER => 0,
            //是否跟随跳转
            CURLOPT_FOLLOWLOCATION=>true,
            CURLOPT_POSTFIELDS => http_build_query($postData['data']),
            CURLOPT_HTTPHEADER => array(
                "Cache-Control: no-cache",
                "Content-Type: application/x-www-form-urlencoded",
            ),
        ));
        $response = curl_exec($curl);
        $err = curl_error($curl);
        curl_close($curl);
        if ($err) {
            return false;
        } else {
            return ['code' => 0, 'data' => $response];
        }
    }

}

/**
 * 获取阶乘
 * @param int $n
 * @return float|int
 */
function factorial(int $n):int
{
    return array_product(range(1, $n));
}

/**
 * 排列数
 * @param int $n 数组长度
 * @param int $m 排列长度
 * @return float|int
 */
function A($n, $m)
{
    return factorial($n) / factorial($n - $m);
}

/**
 * 组合数
 * @param int $n 数组长度
 * @param int $m 排列长度
 * @return float|int
 */
function C($n, $m)
{
    return A($n, $m) / factorial($m);
}

/**
 * 获取组合
 * @param array $a 一个有序数组
 * @param int $m 组合长度
 * @return array
 */
function combination(array $a, int $m): array
{
    //定义空返回结果
    $r = [];
    //数组长度
    $n = count($a);
    //m 只能是小于数组长度的正整数
    if ($m <= 0 || $m > $n) {
        return $r;
    }
    //循环
    for ($i = 0; $i < $n; $i++) {
        //获取一个初始数
        $t = [$a[$i]];
        if ($m == 1) {
            //长度为1时直接给结果赋值
            $r[] = $t;
        } else {
            //取出初始值后面的数组
            $b = array_slice($a, $i + 1);
            //递归
            $c = combination($b, $m - 1);
            foreach ($c as $v) {
                //array_merge() 函数把一个或多个数组合并为一个数组
                $r[] = array_merge($t, $v);
            }
        }
    }

    return $r;
}

/**
 *
 * 全排列
 * @param array $a 一个数组
 * @param int $m 组合长度
 * @return array
 */
function arrangement($a, $m)
{
    $r = array();
    $n = count($a);
    if ($m <= 0 || $m > $n) {
        return $r;
    }
    for ($i = 0; $i < $n; $i++) {
        $b = $a;
        //取出$t初始值 $b为剔除初始数的数组
        $t = array_splice($b, $i, 1);
        if ($m == 1) {
            $r[] = $t;
        } else {
            $c = arrangement($b, $m - 1);
            //遍历合并
            foreach ($c as $v) {
                $r[] = array_merge($t, $v);
            }
        }
    }

    return $r;
}


$res = arrangement(range(1, 3), 2);
var_dump($res);
die;