热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

利用Nginx代理输出缩放图片

:本篇文章主要介绍了利用Nginx代理输出缩放图片,对于PHP教程有兴趣的同学可以参考一下。
nginx 配置文件:

# document ppt convert  Configuration.
upstream document.polyv.net {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name document.polyv.net;
    index index.html index.htm;
    charset utf-8;
    client_max_body_size    1000m;

    # ignore favicon.ico not exist.
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    # not allow to visit hidden files.
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    location / {
        if ($request_filename ~* ^.*?\.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx)$) {
            add_header Content-Disposition: 'attachment;';
            add_header Content-Type: 'APPLICATION/OCTET-STREAM';
        }

        proxy_pass http://document.polyv.net;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REQUEST_HOST $host;

        # include proxy.conf;
        charset UTF-8;
    }

    # user upload files
    location /images/ {
            #expires 7d;
        alias /data03/ovp/blobs/;
            proxy_store on;
            proxy_store_access user:rw group:rw all:rw;
            proxy_set_header Accept-Encoding "";
            if ( !-f $request_filename ) {
                proxy_pass http://document.polyv.net;
            }
    }

    location /blobs/ {
            #expires 7d;
        alias /data03/ovp/blobs/;
    }

        location /preview/images/ {
            #expires 7d;
            alias /data03/ovp/blobs/;
            proxy_store on;
            proxy_store_access user:rw group:rw all:rw;
            proxy_set_header Accept-Encoding "";
            if ( !-f $request_filename ) {
                proxy_pass http://document.polyv.net;
            }
        }

}



代理输出缩放图片

package com.document.handle.controller;import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;import com.document.tool.ImageMagickUtils;
import com.document.tool.SystemConfig;@Controller
public class ImageAgentController {

    private static final Logger LOG = LoggerFactory.getLogger(ImageAgentController.class);/**
     * ppt预览图片代理输出
     * @throws IOException
     */
    @RequestMapping("/preview/images/{year}/{month}/{md5id}/{preview}/{filename}.{ext}")
    public void cropImage(@PathVariable String year, @PathVariable String month, @PathVariable String md5id,
            @PathVariable String preview, @PathVariable String filename, @PathVariable String ext,
            HttpServletRequest request, HttpServletResponse response) throws IOException {
        // String rootDir = "/data03/ovp/blobs/";
        String rootDir = SystemConfig.getBlobDirectory();
        String Oname= filename.substring(1, filename.length());// 原图文件名
        String dirString = rootDir + year + "/" + month + "/" + md5id + "/" + oname + "." + ext;
        String targetFileString = rootDir + year + "/" + month + "/" + md5id + "/preview/" + filename + "." + ext;        //如果原图存在
        File originImage = new File(oname);
        if(originImage.exists()){
            LOG.info("corpImage..." + dirString + " -> " + targetFileString);
            File newfile = new File(targetFileString);
            String pathString = newfile.getParent();
            LOG.info("pathString...{} {}", pathString);
            File pathFile = new File(pathString);
            if (!pathFile.exists()) {
                LOG.info("---create file---");
                pathFile.mkdirs();
            }
            boolean status = ImageMagickUtils.scale(dirString, targetFileString, 240, 180);
            if (status) {
                response.reset();
                response.setContentType("image/" + ext);                java.io.InputStreamin = new java.io.FileInputStream(targetFileString);
                // FilenameUrlUtils.getImageFilename(targetFileString);                if (in != null) {
                    byte[] b = new byte[1024];
                    int len;
                    while ((len = in.read(b)) != -1) {
                        response.getOutputStream().write(b);
                    }

                    in.close();
                }
            }
        }else{
            LOG.info("原图目录不存在-preview:{}",dirString); 
        }
    }


    /**
     * ppt固定尺寸图片代理输出
     * @throws IOException
     * http://document.polyv.net/images/2016/03/de37d2ceb11ac068c18c5e4428541075/jpg-3/1000x540.png
     *
     * http://document.polyv.net/images/2016/03/de37d2ceb11ac068c18c5e4428541075/jpg-3.png
     */
    @RequestMapping("/images/{year}/{month}/{md5id}/{filename}/{width}x{height}.{ext}")
    public void cropfixedImage(@PathVariable String year, @PathVariable String month, @PathVariable String md5id,
            @PathVariable String filename, @PathVariable Integer width, @PathVariable Integer height, @PathVariable String ext,
            HttpServletRequest request, HttpServletResponse response) throws IOException {
        // String rootDir = "/data03/ovp/blobs/";
        String rootDir = SystemConfig.getBlobDirectory();
        //String Oname= filename.substring(1, filename.length());// 原图文件名
        String dirString = rootDir + year + "/" + month + "/" + md5id + "/" + ( filename + "." + ext);
        String targetFileString = rootDir + year + "/" + month + "/" + md5id + "/" + filename + "/" + (width + "x" + height + "." + ext);        //如果原图存在
        File originImage = new File(dirString);
        if(originImage.exists()){
            File targetFileStringFile = new File(targetFileString);
            if(!targetFileStringFile.exists()){
                LOG.info("corpImage..." + dirString + " -> " + targetFileString);
                File newfile = new File(targetFileString);
                String pathString = newfile.getParent();
                LOG.info("pathString...{} {}", pathString);
                File pathFile = new File(pathString);
                if (!pathFile.exists()) {
                    LOG.info("---create file---");
                    pathFile.mkdirs();
                }
                ImageMagickUtils.resizeWH(dirString, targetFileString,width,height);
            }
            response.setContentType("image/" + ext);
            java.io.InputStreamin = null;
            try{
                in = new java.io.FileInputStream(targetFileString);
                response.setContentLength(in.available());
                byte[] buffer = new byte[1024];
                int count = 0;
                while ((count = in.read(buffer)) > 0) {
                    response.getOutputStream().write(buffer, 0, count);
                }
                response.flushBuffer();
            }catch(Exception e){
                e.printStackTrace();
            }finally {
                try {
                    in.close();
                } catch (Exception e) {

                }
            }
        }else{
            LOG.info("原图目录不存在:{}",dirString);
        }




    }


    /**
     * 图片下载
     */
    @RequestMapping("get/image/data")
    public void downloadImage(HttpServletRequest request, HttpServletResponse response) throws IOException {  
        String filePath = ServletRequestUtils.getStringParameter(request, "filePath", ""); //图片访问路劲
        String fileName = ServletRequestUtils.getStringParameter(request, "fileName", ""); //名称        if(StringUtils.isNotBlank(filePath) || StringUtils.isNotBlank(fileName)){
            String destUrl = filePath;
            //LOG.info("--------------"+filePath); 
            String fileFormat=filePath.substring(filePath.lastIndexOf("."));
            //String name=fileName.trim()+fileFormat;
            String name=filePath.substring(filePath.lastIndexOf("/")+1, filePath.length()); 
            //File f = new File(filePath);
            //response.setHeader("Content-Disposition", "attachment; filename="+java.net.URLEncoder.encode(f.getName(),"UTF-8"));  
            //LOG.info("--------------"+f.getName());            // 建立链接  
            URL url = new URL(destUrl);  
            HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection();  
            // 连接指定的资源  
            httpUrl.connect();  
            // 获取网络输入流  
            BufferedInputStream bis = new BufferedInputStream(httpUrl.getInputStream());              Integer lenf=httpUrl.getContentLength();
            //String lenf=this.getFileLength(4189053, 7189053);
            response.setContentType("application/x-msdownload"); 
            response.setHeader("Content-Length", lenf.toString());//文件大小值5几M
            response.setHeader("Content-Disposition", "attachment; filename="+java.net.URLEncoder.encode(name,"UTF-8"));
            OutputStream out = response.getOutputStream();
            byte[] buf = new byte[1024];  
            if (destUrl != null) {  
                BufferedInputStream br = bis;  
                int len = 0;  
                while ((len = br.read(buf)) > 0){  
                    out.write(buf, 0, len);  
                }                 
                br.close();  
            }  
            out.flush();  out.close();  
        }

    } 

}

图片缩放的业务

package com.document.tool;

import java.io.IOException;

import javax.swing.ImageIcon;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 使用ImageMagick对图片文件进行处理的工具类。
 * @author XingNing OU
 */publicabstractclassImageMagickUtils {privatestaticfinal String EXECUTABLE_COnVERT= "/usr/bin/convert"; // convert命令privatestaticfinal String EXECUTABLE_COMPOSITE = "/usr/bin/composite"; // composite命令privatestaticfinallong EXECUTE_TIMEOUT = 30 * 60 * 1000L; // 30 minutesprivatestaticfinal Logger LOG = LoggerFactory.getLogger(ImageMagickUtils.class);

    /**
     * 执行图片处理的命令。
     * @param cmdLine 待执行的命令
     * @return exitValue,一般等于0时表示正常运行结束
     * @throws ExecuteException 命令执行失败时抛出此异常
     * @throws IOException 当发生IO错误时抛出此异常
     * @throws InterruptedException 当等待异步返回结果被中断时抛出此异常
     */publicstaticintexecuteCommandLine(CommandLine cmdLine) throws ExecuteException, IOException,
    InterruptedException {
        Executor executor = new DefaultExecutor();
        executor.setExitValue(0);

        // Kill a run-away process after EXECUTE_TIME milliseconds.
        ExecuteWatchdog watchdog = new ExecuteWatchdog(EXECUTE_TIMEOUT);
        executor.setWatchdog(watchdog);

        // Execute the print job asynchronously.
        DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
        executor.execute(cmdLine, resultHandler);

        // Some time later the result handler callback was invoked.
        resultHandler.waitFor();

        // So we can safely request the exit value.return resultHandler.getExitValue();
    }

    /**
     * 按照高宽比例缩小图片。
     * @param src 源图片
     * @param dst 目标图片
     * @param width 图片图片的宽度
     * @param height 目标图片的高度
     * @return 是否处理成功
     */publicstaticbooleanscale(String src, String dst, int width, int height) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-scale");
        cmdLine.addArgument(width + "x" + height);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("缩略图片时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 按照高宽比例缩小图片。
     * @param src 源图片
     * @param dst 目标图片
     * @param width 图片图片的宽度
     * @param height 目标图片的高度
     * @return 是否处理成功
     */publicstaticbooleanthumbnail(String src, String dst, int width, int height) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-thumbnail");
        cmdLine.addArgument(width + "x" + height);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("缩略图片时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 添加图片水印。
     * @param src 源图片
     * @param dst 目标图片
     * @param logofile 水印图片
     * @param dissolve 和水印的融合度,0-100的数字
     * @param gravity 叠放方向,East,West,North,South,NorthEast,NorthWest,SouthEast,SouthWest
     * @return 是否处理成功
     */publicstaticbooleandrawLogo(String src, String dst, String logofile, int dissolve, String gravity) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_COMPOSITE);
        cmdLine.addArgument("-dissolve");
        cmdLine.addArgument(dissolve + "%");
        cmdLine.addArgument("-gravity");
        cmdLine.addArgument(gravity);
        cmdLine.addArgument(logofile);
        cmdLine.addArgument(src);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("添加图片水印时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 添加图片水印。
     * @param src 源图片
     * @param dst 目标图片
     * @param logofile 水印图片
     * @param dissolve 和水印的融合度,0-100的数字
     * @param x 水印距离左下角的距离
     * @param y 水印距离右下角的距离
     * @return 是否处理成功
     */publicstaticbooleandrawLogo(String src, String dst, String logofile, int dissolve, int x, int y) {
        ImageIcon icon = new ImageIcon(src);
        int width = icon.getIconWidth(); // 源图的宽int height = icon.getIconHeight(); // 源图的高        String _x = String.valueOf(width - x); // 在x轴上水印图片的左上顶点距离图片左上角的距离
        String _y = String.valueOf(height - y); // 在y轴上水印图片的左上顶点距离图片左上角的距离// 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_COMPOSITE);
        cmdLine.addArgument("-dissolve");
        cmdLine.addArgument(dissolve + "%");
        cmdLine.addArgument("-geometry");
        cmdLine.addArgument(_x + "+" + _y);
        cmdLine.addArgument(logofile);
        cmdLine.addArgument(src);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("添加图片水印时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 裁剪图片。
     * @param src 源图片
     * @param dst 目标图片
     * @param width 目标宽度
     * @param height 目标高度
     * @param left 裁剪位置:距离左边的像素
     * @param top 裁剪位置:距离上边的像素
     * @return 是否处理成功
     */publicstaticbooleancrop(String src, String dst, int width, int height, int left, int top) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-crop");
        cmdLine.addArgument(width + "x" + height + "+" + left + "+" + top);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("裁剪图片时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 获取矩形的小图。
     * @param src 源图片
     * @param dst 目标图片
     * @param width 目标宽度
     * @param height 目标高度
     * @param left 裁剪位置:距离左边的像素
     * @param top 裁剪位置:距离上边的像素
     * @return 是否处理成功
     */publicstaticbooleancropRect(String src, String dst, int width, int height, int left, int top) {
        ImageIcon icon = new ImageIcon(src);
        int origWidth = icon.getIconWidth();
        int origHeight = icon.getIconHeight();
        int[] s = newint[2];
        if (origWidth // 以宽为标准
            s = getSize(origWidth, origHeight, width, height, 1);
        } else {// 以高为标准
            s = getSize(origWidth, origHeight, width, height, 2);
        }

        if (thumbnail(src, dst, s[0], s[1])) {
            return crop(src, dst, width, height, left, top);
        }
        returnfalse;
    }

    /**
     * 加边框。
     * @param src 源图片
     * @param dst 目标图片
     * @param borderWidth 边框的宽度
     * @param borderHeight 边框的高度
     * @param borderColor 边框的颜色
     * @return 是否处理成功
     */publicstaticbooleanborder(String src, String dst, int borderWidth, int borderHeight, String borderColor) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument("-bordercolor");
        cmdLine.addArgument(borderColor);
        cmdLine.addArgument("-border");
        cmdLine.addArgument(borderWidth + "x" + borderHeight);
        cmdLine.addArgument(src);
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("加图片边框时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 转换图片格式。
     * @param src 源图片
     * @param dst 目标图片
     * @param format 转换的格式
     * @return 是否处理成功
     */publicstaticbooleanformat(String src, String dst, String format) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-format");
        cmdLine.addArgument("'" + format + "'");
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("转换图片格式时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 转换无限极的TIFF图片。
     */publicstaticbooleanconvertTiff(String src, String dst) {        
     // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-colorspace");
        cmdLine.addArgument("RGB");
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("转换图片格式时发生异常,Cause: ", e);
            returnfalse;
        }
    }


    /**
     * 获得要压缩图片的大小。
     * @param w 图片的原宽度
     * @param h 图片的原高度
     * @param width 标准宽
     * @param height 标准高
     * @param type 类型 1-以宽为标准压缩 2-以高为标准压缩 3-以比例大小压缩
     * @return size[0]-要压缩的宽度, size[1]-要压缩的高度
     */publicstaticint[] getSize(double w, double h, double width, double height, int type) {
        if (w // 如果原宽度比标准宽度小
            width = w;
        }
        if (h // 如果原高度比标准高度小
            height = h;
        }
        double scale = w / h;
        switch (type) {
            case1:
                height = width / scale;
                break;
            case2:
                width = height * scale;
                break;
            case3:
                if (width / height > scale) {
                    width = height * scale;
                } elseif ((width / height) break;
        }
        int[] size = newint[2];
        size[0] = (int) width;
        size[1] = (int) height;
        return size;
    }


    /**
     * 指定宽度。
     * @param src
     * @param width
     * @param dst
     */publicstaticbooleanresize(String src, int width, String dst) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-resize");
        cmdLine.addArgument(width + "");
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("缩略图片时发生异常,Cause: ", e);
            returnfalse;
        }
    }

    /**
     * 指定宽度、高度。
     * @param src
     * @param width
     * @param dst
     */publicstaticbooleanresizeWH(String src,String dst, int width, int height ) {
        // 构建命令
        CommandLine cmdLine = new CommandLine(EXECUTABLE_CONVERT);
        cmdLine.addArgument(src);
        cmdLine.addArgument("-resize");
        cmdLine.addArgument(width + "x" + height +"!");
        cmdLine.addArgument(dst);

        try {
            executeCommandLine(cmdLine);
            returntrue;
        } catch (Exception e) {
            LOG.error("缩略图片时发生异常,Cause: ", e);
            returnfalse;
        }
    }
}

服务器上要安装imagemagick,

').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
  • ').text(i)); }; $numbering.fadeIn(1700); }); });

    以上就介绍了利用Nginx 代理输出缩放图片,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

  • 推荐阅读
    • 本文详细探讨了如何根据不同的应用场景选择合适的PHP版本,包括多版本切换技巧、稳定性分析及针对WordPress等特定平台的版本建议。 ... [详细]
    • 笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系& ... [详细]
    • 搭建个人博客:WordPress安装详解
      计划建立个人博客来分享生活与工作的见解和经验,选择WordPress是因为它专为博客设计,功能强大且易于使用。 ... [详细]
    • 在使用 Nginx 作为服务器时,发现 Chrome 能正确从缓存中读取 CSS 和 JS 文件,而 Firefox 却无法有效利用缓存,导致加载速度显著变慢。 ... [详细]
    • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
    • 本文介绍了 PHP 的基本概念、服务器与客户端的工作原理,以及 PHP 如何与数据库交互。同时,还涵盖了常见的数据库操作和安全性问题。 ... [详细]
    • 汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ... [详细]
    • Canopy环境安装与使用指南
      《利用Python进行数据分析》一书推荐使用EPDFree版本的环境,然而随着技术的发展,目前更多人倾向于使用Canopy。本文将详细介绍Canopy的安装及使用方法。 ... [详细]
    • 【MySQL】frm文件解析
      官网说明:http:dev.mysql.comdocinternalsenfrm-file-format.htmlfrm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果 ... [详细]
    • Nginx 启动命令及 Systemctl 配置详解
      本文详细介绍了在未配置和已配置 Systemctl 的情况下启动 Nginx 的方法,并提供了详细的配置步骤和命令示例。 ... [详细]
    • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
    • 精选10款Python框架助力并行与分布式机器学习
      随着神经网络模型的不断深化和复杂化,训练这些模型变得愈发具有挑战性,不仅需要处理大量的权重,还必须克服内存限制等问题。本文将介绍10款优秀的Python框架,帮助开发者高效地实现分布式和并行化的深度学习模型训练。 ... [详细]
    • 流处理中的计数挑战与解决方案
      本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
    • mysql 授权!!
      为什么80%的码农都做不了架构师?MySQL的权限系统围绕着两个概念:认证-确定用户是否允许连接数据库服务器授权-确定用户是否拥有足够的权限执 ... [详细]
    • Centos7 Tomcat9 安装笔记
      centos7,tom ... [详细]
    author-avatar
    暗罗华怡
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有