自己的web服务器项目-request请求和response响应处理
yuyutoo 2024-10-12 01:23 1 浏览 0 评论
我们经常使用别人的服务器进行构建网站,现在我们就自己来写一个自己的服务来使用。
准备工作:下载所需的题材及文档
注:完整项目下载
一、request请求获取
1、了解request请求
在写服务器之前,我们需要知道客户端发送给我们哪些信息?以及要求我们返回哪些信息?经过测试我们能够知道用户客户端发送的信息有以下几点:
客户端发送到服务器端的请求消息,我们称之为请求(request),其实就是一个按照http协议的规则拼接而成的字符串,Request请求消息包含三部分: 请求行 消息报头 请求正文
第一部 请求行
格式:
Method Request-URI HTTP-Version CRLF
各部分分别为:
Method表示请求方法;一般为GET或者POST ;Request-URI是一个统一资源标识符; HTTP-Version表示请求的HTTP协议版本; CRLF表示回车和换行
例如:
GET /test.html HTTP/1.1
第二部 消息报头 http header
例如:
GET /test.html HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en;q=0.8,zh;q=0.5,en-US;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
第三部 请求正文 http body
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的字符串信息
注意:在第二部分header和第三部分body之间有个空行,除非没有请求正文(如果你想要亲自看到效果,请参考:浏览器中GET和POST的区别),这是因为用户在浏览网页时提交给服务器的信息是不同的
2、实现
经过以上分析,我们就能够清楚的知道,客户端发送给服务器的请求,请求信息有使用的协议、请求的方法、请求的资源路径、请求的消息报头、判断请求的内容是否为静态资源、判断请求的内容是否为动态资源、判断是否为空请求,为了使用的方便,我们需要将其封装起来,总不能使用一次读取一次吧,这样做实在是太浪费系统资源与时间了,如下代码,就是一个接口类,用于获取客户端发送过来的属性
package com.sample.http; import java.util.Map; // http协议的请求 public interface HttpRequest { //获得请求的协议 public String getProtocol(); //获得请求的方法 public String getRequestMethod(); //获得请求的路径 public String getRequestPath(); //获得请求的消息报头 public Map<String,String> getRequestHeader(); //根据参数的名字获得请求带过来的参数值 public String getParameter(String parameterName); //判断当前请求的否是静态资源 public boolean isStaticResource(); //判断当前请求的否是动态资源 public boolean isDynamicResource(); //判断当前请求的否是为空请求(有些浏览器会自动发送空请求) public boolean isNullRequest(); }
有了接口类之后,我们就可以创建类进行实现,下面就是实现类,用于对各个方法进行处理:
package com.sample.http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class HttpRequestImpl implements HttpRequest{ //客户端的Socket private Socket s; private InputStream is=null;//输入流 private BufferedReader br=null; private HashMap<String,String> hmHeader=new HashMap<String,String>();//消息报头 private HashMap<String,String> hmparameters=new HashMap<String, String>();//参数集合 private boolean isNullRequest=false;//是否为空请求,默认false private String protocol=null;//请求协议 private String requestMethod=null;//请求方法 private String requestPath=null;//请求路径 public HttpRequestImpl(Socket s) { this.s=s; getInfos();//调用方法 } private void getInfos()//定义一个方法,用于处理获取的客户端信息 { try { is=s.getInputStream(); br=new BufferedReader(new InputStreamReader(is)); //解析第一行 String str; str=br.readLine();//readLine使用回车换行判断一行是否结束 if(str==null) { isNullRequest=true; return; } parseRequestMethodPathProtocol(str);//调用自己创建在本类里边的方法处理第一行信息,方法在后面 //解析第二行---第八行 String header=null; //判断是否结束,如果结束就退出,这里的判断按较为饶人 //首先应该明确br.readLine()的内容,当为true是对应的情况 //也就是说当“”(中间没有空格)与br.readLine()相等时,就进入到while中 while(!"".equals((header=br.readLine()))){ parseRequestHeader(header); } //post和get if(br.ready())//post//POST提交方式判断,如果还有下一行就继续读取信息 { char[] buf=new char[1024]; int len=br.read(buf);//使用字节进行读取,因为这一行没有回车换行,readLine无法判断是否结束 String parameter=new String(buf,0,len); parseRequestParamByPost(parameter);//调用自己创建在本类里边的方法处理POST方式提交的正文信息 } else {//get,get参数的位置在第一行连接处 parseRequestParamByGet(requestPath);//调用自己创建在本类里边的方法处理GET方式提交的正文信息 } } catch (Exception e) { e.printStackTrace(); } } //GET方法处理 private void parseRequestParamByGet(String requestPath2) { String []str1=requestPath2.split("[?]");//使用“?”分割字符串 if(str1.length==2) { parseRequestParamByPost(str1[1]); } this.requestPath=str1[0]; } //POST方法处理 private void parseRequestParamByPost(String parameter) { String[] strs=parameter.split("&"); if(strs.length>=1) { for(String str:strs) { String [] sp=str.split("="); hmparameters.put(sp[0],sp[1]); } } } //解析第二行到第八行 private void parseRequestHeader(String header) throws Exception{ String[] headHost=header.split(": "); if(headHost.length!=2) { throw new Exception("消息报头异常,请重新提交"); } hmHeader.put(headHost[0],headHost[1]); } //解析第一行 private void parseRequestMethodPathProtocol(String str) throws Exception { String[] protocolMethodPath=new String[3];//由于第一行含有三个内容,分割后需要三个String存储 protocolMethodPath=str.split(" ");//使用空格分割 if(protocolMethodPath.length==3) { requestMethod=protocolMethodPath[0]; requestPath=protocolMethodPath[1]; protocol=protocolMethodPath[2]; } else { throw new Exception("首行参数不合适,请重新提交"); } } //获得请求的协议 public String getProtocol() { return protocol; } //获得请求的方法 public String getRequestMethod(){ return requestMethod; } //获得请求的路径 public String getRequestPath(){ return requestPath; } //获得请求的消息报头 public Map<String,String> getRequestHeader(){ return this.hmHeader; } //根据参数的名字获得请求带过来的参数值 public String getParameter(String parameterName){ return hmparameters.get(parameterName); } //判断当前请求的否是静态资源 public boolean isStaticResource(){ return true; } //判断当前请求的否是动态资源 public boolean isDynamicResource(){ return true; } //判断当前请求的否是为空请求(有些浏览器会自动发送空请求) public boolean isNullRequest(){ return isNullRequest; } }
以上内容是对客户端(浏览器)请求内容的处理,即如何进行包装客户端请求的信息,并且将其包装成一个统一的整体,既然能够获取浏览器的内容,那么,我们就必须采取一定的措施告诉浏览器我们找到了你想要的文件,并且将返回给客户端,下面我们就来实现如何返回给客户端想要的信息
二、response响应处理
1、了解response响应
服务器在接收和解释客户端的请求消息后,服务器会返回给客户端一个HTTP响应消息,我们称之为响应(response)。其实也是一个按照http协议的规则拼接而成的一个字符串
HTTP响应也是由三个部分组成,分别是: 响应状态行、消息报头、响应正文
第一部分 响应状态行
格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
例如:
HTTP/1.1 200 OK
各部分分别为:
HTTP-Version表示服务器HTTP协议的版本;
Status-Code表示服务器发回的响应状态代码;
Reason-Phrase表示状态代码的文本描述。
CRLF表示回车和换行
第二部分 消息报头
HTTP消息报头包括普通报头、请求报头、响应报头、实体报头这四大类。
每一个 报头域 都是由 名字+冒号+空格+值 组成,消息报头域的名字不区分大小写。它们的作用是描述 客户端或者服务器 的属性
1.普通报头:即可用于请求,也可用于响应,是作为一个整体而不是特定资源与事务相关联。
2.请求报头:允许客户端传递关于自身信息和希望的响应形式。
3.响应报头:允许服务器传递关于自身信息的响应。
4.实体报头:定义被传送资源的信息。即可用于请求,也可用于响应。
什么是 MIME Type?
首先,我们要了解浏览器是如何处理内容的。在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有 Flash ……那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME Type,也就是该资源的媒体类型。媒体类型通常是通过 HTTP 协议,由 Web 服务器告知浏览器的,更准确地说,是通过响应的消息报头里面的属性 Content-Type 来表示的,例如:Content-Type: text/HTML表示内容是 text/HTML 类型,也就是超文本文件。为什么是“text/HTML”而不是“HTML/text”或者别的什么?MIME Type 不是个人指定的,是经过 ietf 组织协商,以 RFC 的形式作为建议的标准发布在网上的,大多数的 Web 服务器和用户代理都会支持这个规范 (顺便说一句,Email 附件的类型也是通过 MIME Type 指定的)。
通常只有一些在互联网上获得广泛应用的格式才会获得一个 MIME Type,如果是某个客户端自己定义的格式,一般只能以 application/x- 开头。XHTML 正是一个获得广泛应用的格式,因此,在 RFC 3236 中,说明了 XHTML 格式文件的 MIME Type 应该是 application/xHTML+XML。当然,处理本地的文件,在没有人告诉浏览器某个文件的 MIME Type 的情况下,浏览器也会做一些默认的处理,这可能和你在操作系统中给文件配置的 MIME Type 有关。比如在 Windows 下,打开注册表的“HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type”主键,你可以看到所有 MIME Type 的配置信息
每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
常见的MIME类型
超文本标记语言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF图形 .gif image/gif
JPEG图形 .ipeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
第三部分 响应正文
响应正文就是服务器返回的资源的内容
2、实现
首先,我们需要进行抽象,即将浏览器想要的信息,即如下内容包装起来,如下所示,我们将其包装成一个接口,在抽象时我们必须认识到用户可能会犯的错误,所以尽量使用重载的方法进行避免,在下面的接口中,使用了重载进行处理部分方法:
package com.sample.http; import java.io.OutputStream; import java.io.PrintWriter; //http协议的响应 public interface HttpResponse { //获得一个指向客户端的字节流 public OutputStream getOutputStream()throws Exception; //获得一个指向客户端的字符流 public PrintWriter getPrintWriter()throws Exception; //设置响应的状态行 参数为String类型 public void setStatusLine(String statusCode); //设置响应的状态行 参数为int类型 public void setStatusLine(int statusCode); //设置响应消息报头 public void setResponseHeader(String hName,String hValue); //设置响应消息报头中Content-Type属性 public void setContentType(String contentType); //设置响应消息报头中Content-Type属性 并且同时设置编码 public void setContentType(String contentType,String charsetName); //设置CRLF 回车换行 \r\n public void setCRLF(); //把设置好的响应状态行、响应消息报头、固定空行这三部分写给浏览器 public void printResponseHeader(); //把响应正文写给浏览器 public void printResponseContent(String requestPath); }
在接口中,我们能够看到详细的解释,下面我们就来实现接口中的方法:
package com.sample.http; <pre name="code" class="java">import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; import com.sample.utils.ConfigUtils; import com.sample.utils.StatusCodeUtils; //http协议的响应 public class HttpResponseImpl implements HttpResponse { //声明初始变量 Socket s;//客户端socket OutputStream os;//输出端字节流 BufferedWriter bw;//输出端字符流 PrintWriter pw; StringBuffer sbuffer;//放状态行,\r\n , FileInputStream fis; File file; //构造器 public HttpResponseImpl(Socket s) { this.s=s; System.out.println("HttpRequestImpl(Socket s)"); os=null; bw=null; pw=null; sbuffer=new StringBuffer();//初始化,记得,否则以下的操作会遇见空指针异常 fis=null; file=null; getInfos(); } private void getInfos() { try { os=s.getOutputStream(); bw=new BufferedWriter(new OutputStreamWriter(os,"GBK")); pw=new PrintWriter(bw); } catch (Exception e) { e.printStackTrace(); } } //获得一个指向客户端的字节流 public OutputStream getOutputStream()throws Exception { return os; } //获得一个指向客户端的字符流 public PrintWriter getPrintWriter()throws Exception { return pw; } //设置响应的状态行 参数为String类型 public void setStatusLine(String statusCode) { String str=StatusCodeUtils.getStatusCodeValue(statusCode); //System.out.println(str+"------"+str.length()); sbuffer.append("HTTP/1.1 "+statusCode+" "+str); setCRLF(); } //设置响应的状态行 参数为int类型 public void setStatusLine(int statusCode) { setStatusLine(statusCode+"");//将int类型转化为String类型 } //设置响应消息报头 public void setResponseHeader(String hName,String hValue) { sbuffer.append(hName+": "+hValue); setCRLF(); } //设置响应消息报头中Content-Type属性 public void setContentType(String contentType) { setResponseHeader("Content-Type",contentType); } //设置响应消息报头中Content-Type属性 并且同时设置编码 public void setContentType(String contentType,String charsetName) {//text/html;charset=utf-8 setContentType(";charset= "+charsetName); } //设置CRLF 回车换行 \r\n public void setCRLF() { sbuffer.append("\r\n"); } //把设置好的响应状态行、响应消息报头、固定空行这三部分写给浏览器 public void printResponseHeader() { //设置setResponseLine,setResponseHeader,setResponseType String res=sbuffer.toString(); pw.print(res); pw.flush(); } //把响应正文写给浏览器 public void printResponseContent(String requestPath) { //响应正文 String getPath= requestPath;//客户请求的地址 String webHome=(new ConfigUtils()).getConfigValue("rootPath"); System.out.println("配置文件中目录:"+webHome);//输出从配置文件中获取的地址 file=new File(webHome+getPath); if(file.exists())//如果文件存在就执行 { try { fis=new FileInputStream(file); byte[] buf=new byte[1024]; int len=-1; while((len=fis.read(buf))!=-1) { //String str=buf.toString(); //bw.write(str);//字符流写过去是一个地址,因为写过去之后需要浏览器解析,如果是图片或者其他(图片或视频是字节流)的该怎么解析呢? //System.out.println(str); os.write(buf, 0, len); } bw.flush(); os.flush();//os要不要关??? } catch (IOException e) { e.printStackTrace(); }finally { try { if(bw!=null) bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
在Eclipse中写完以上代码我们会发现,其中有多处错误信息,其原因是我们没有进行创建以上代码所要求的类,现在我们进行创建,其使用方法请参见:java.util 类 Properties ,使用参考中的方法,我们能够进行对所需要的信息进行配置,在以上代码中使用的地方有两处,分别是【注意:这样做的好处是增减了项目的灵活性,用户能够在不查看代码的情况下随时更改配置文件等一些文件的信息,】:
(1)设置状态行处
//设置响应的状态行 参数为String类型 public void setStatusLine(String statusCode) { String str=StatusCodeUtils.getStatusCodeValue(statusCode); //System.out.println(str+"------"+str.length()); sbuffer.append("HTTP/1.1 "+statusCode+" "+str); setCRLF(); }
其中StatusCodeUtils类创建如下所示,而对于status_code.properties文件存放在下载的准备文件中的/webservlet/project/中,直接复制到项目中即可:
package com.sample.utils; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class StatusCodeUtils { private static Properties p; static { InputStream in=null; p=new Properties(); try { //读了xx.properties文件 in=StatusCodeUtils.class.getResourceAsStream("status_code.properties"); //放置到p中,即放properties文件中的key,value p.load(in); } catch (IOException e) { e.printStackTrace(); } finally { if(in!=null) try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } public static String getStatusCodeValue(String status) { return p.getProperty(status); } public static String getStatusCodeValue(int status) { return getStatusCodeValue(status+"");//没有空格 } /*public static void main(String[] args) {//输出测试 //Properties p=new Properties(); // p.setProperty("rootPath","ddd"); //System.out.println(p.get("rootPath")); System.out.println(getStatusCodeValue("304")); System.out.println(getStatusCodeValue("200")); }*/ } (2)响应正文处: //响应正文 String getPath= requestPath;//客户请求的地址 String webHome=(new ConfigUtils()).getConfigValue("rootPath"); System.out.println("配置文件中目录:"+webHome);//输出从配置文件中获取的地址 file=new File(webHome+getPath);
在响应正文中使用了ConfigUtils类进行了项目路径的获取,代码如下所示,对于config.properties(注意:此文件中文件路径应该注意,我使用的是Linux系统,文件结构是/home/***,而对于windows系统,目录结构为:"C://webapps/*****,最好在地址栏复制地址,写到配置中")文件也在准备文件中,请自行下载,然后复制到项目中:就是下面这个东西,路径配置合适,然后你就可以将自己的项目放在webapps目录下,让自己的电脑作为服务器供其他人访问自己的网站了
ConfigUtils路径配置类,用于获取项目文件目录位置
package com.sample.utils; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Properties; public class ConfigUtils { private static Properties p; static { InputStream in=null; OutputStream on=null; p=new Properties(); try { //读了xx.properties文件 in=ConfigUtils.class.getResourceAsStream("config.properties"); //放置到p中,即放properties文件中的key,value p.load(in); } catch (IOException e) { e.printStackTrace(); } finally { if(in!=null) try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } public static String getConfigValue(String config) { return p.getProperty(config); } public static void main(String[] args) {//输出测试 // Properties p=new Properties(); // p.setProperty("rootPath","ddd"); // System.out.println(p.get("rootPath")); System.out.println(getConfigValue("rootPath")); } }
到此为止,我们已经实现了服务器的主要任务,接受请求和处理请求,下面我们进行测试:
写一个测试类如下:
package com.sample.http; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class ServerTest { public static void main(String[] args) { //声明变量 ServerSocket ss=null; Socket s=null; boolean flag=true; try { int port=10002; System.out.println("Server Port:"+port); ss=new ServerSocket(port); //while(flag) { //接受客户端发送过来的Socket s=ss.accept(); HttpRequestImpl request=new HttpRequestImpl(s); // 用于测试收到的信息 System.out.println("获取的路径:"+request.getRequestPath()); System.out.println("获取的:"+request.getProtocol()); System.out.println("获取的:"+request.getRequestMethod()); System.out.println(request.getParameter("name")); System.out.println(request.getParameter("id")); Map<String,String> m=request.getRequestHeader(); Set<Entry<String,String>> set=m.entrySet(); Iterator it=set.iterator(); while(it.hasNext()) { Entry entry=(Entry<String, String> )it.next(); System.out.println(entry.getKey()+"----"+entry.getValue()); } //写响应给浏览器 /* * 封装: * */ //输出流 HttpResponseImpl response=new HttpResponseImpl(s); response.setStatusLine(200); response.setContentType("text/html"); response.printResponseHeader(); response.setCRLF(); response.printResponseHeader(); response.printResponseContent(request.getRequestPath()); //用于输出信息 } } catch (IOException e) { e.printStackTrace(); } } }
在浏览器中输入地址回车:http://127.0.0.1:10002/test.html?id=1212&name=suguniang ,能够看到浏览器解析后的界面,当其他电脑访问时(其他电脑指的是同一个域内的),只要将127.0.0.1修改为本地的ip地址即可
此时控制台上也输出相应的信息:
相关推荐
- MySQL5.5+配置主从同步并结合ThinkPHP5设置分布式数据库
-
前言:本文章是在同处局域网内的两台windows电脑,且MySQL是5.5以上版本下进行的一主多从同步配置,并且使用的是集成环境工具PHPStudy为例。最后就是ThinkPHP5的分布式的连接,读写...
- thinkphp5多语言怎么切换(thinkphp5.1视频教程)
-
thinkphp5多语言进行切换的步骤:第一步,在配置文件中开启多语言配置。第二步,创建多语言目录。相关推荐:《ThinkPHP教程》第三步,编写语言包。视图代码:控制器代码:效果如下:以上就是thi...
- 基于 ThinkPHP5 + Bootstrap 的后台开发框架 FastAdmin
-
FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。主要特性基于Auth验证的权限管理系统支持无限级父子级权限继承,父级的管理员可任意增删改子级管理员及权限设置支持单...
- Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示
-
本文实例讲述了Thinkphp5.0框架实现控制器向视图view赋值及视图view取值操作。分享给大家供大家参考,具体如下:Thinkphp5.0控制器向视图view的赋值方式一(使用fetch()方...
- thinkphp5实现简单评论回复功能(php评论回复功能源码下载)
-
由于之前写评论回复都是使用第三方插件:畅言所以也就没什么动手,现在证号在开发一个小的项目,所以就自己动手写评论回复,没写过还真不知道评论回复功能听着简单,但仔细研究起来却无法自拔,由于用户量少,所以...
- ThinkPHP框架——实现定时任务,定时更新、清理数据
-
大家好,我是小蜗牛,今天给大家分享一下,如何用ThinkPHP5.1.*版本实现定时任务,例如凌晨12点更新数据、每隔10秒检测过期会员、每隔几分钟发送请求保证ip的活性等本次分享,主要用到一个名为E...
- BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统
-
BeyongCms内容管理系统(简称BeyongCms)BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统,适用于企业Cms,个人站长等,针对移动App、小程序优化;提供完善简...
- YimaoAdminv3企业建站系统,使用 thinkphp5.1.27 + mysql 开发
-
介绍YimaoAdminv3.0.0企业建站系统,使用thinkphp5.1.27+mysql开发。php要求5.6以上版本,推荐使用5.6,7.0,7.1,扩展(curl,...
- ThinkAdmin-V5开发笔记(thinkpad做开发)
-
前言为了快速开发一款小程序管理后台,在众多的php开源后台中,最终选择了基于thinkphp5的,轻量级的thinkadmin系统,进行二次开发。该系统支持php7。文档地址ThinkAdmin-V5...
- thinkphp5.0.9预处理导致的sql注入复现与详细分析
-
复现先搭建thinkphp5.0.9环境...
- thinkphp5出现500错误怎么办(thinkphp页面错误)
-
thinkphp5出现500错误,如下图所示:相关推荐:《ThinkPHP教程》require():open_basedirrestrictionineffect.File(/home/ww...
- Thinkphp5.0极速搭建restful风格接口层
-
下面是基于ThinkPHPV5.0RC4框架,以restful风格完成的新闻查询(get)、新闻增加(post)、新闻修改(put)、新闻删除(delete)等server接口层。1、下载Thin...
- 基于ThinkPHP5.1.34 LTS开发的快速开发框架DolphinPHP
-
DophinPHP(海豚PHP)是一个基于ThinkPHP5.1.34LTS开发的一套开源PHP快速开发框架,DophinPHP秉承极简、极速、极致的开发理念,为开发集成了基于数据-角色的权限管理机...
- ThinkPHP5.*远程代码执行高危漏洞手工与升级修复解决方法
-
漏洞描述由于ThinkPHP5框架对控制器名没有进行足够的安全检测,导致在没有开启强制路由的情况下,黑客构造特定的请求,可直接GetWebShell。漏洞评级严重影响版本ThinkPHP5.0系列...
- Thinkphp5代码执行学习(thinkphp 教程)
-
Thinkphp5代码执行学习缓存类RCE版本5.0.0<=ThinkPHP5<=5.0.10Tp框架搭建环境搭建测试payload...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- MySQL5.5+配置主从同步并结合ThinkPHP5设置分布式数据库
- thinkphp5多语言怎么切换(thinkphp5.1视频教程)
- 基于 ThinkPHP5 + Bootstrap 的后台开发框架 FastAdmin
- Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示
- thinkphp5实现简单评论回复功能(php评论回复功能源码下载)
- ThinkPHP框架——实现定时任务,定时更新、清理数据
- BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统
- YimaoAdminv3企业建站系统,使用 thinkphp5.1.27 + mysql 开发
- ThinkAdmin-V5开发笔记(thinkpad做开发)
- thinkphp5.0.9预处理导致的sql注入复现与详细分析
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)