목차
2. [代码]CLS_SCACHER   
3. [代码]CLS_ECACHER    
4. [代码]get_departments.php  
5. [代码]get_users.php  
6. [代码]get_users_complex.php  
php教程 PHP源码 使用etag和文件缓存降低服务器数据库压力

使用etag和文件缓存降低服务器数据库压力

May 23, 2016 pm 04:38 PM
php

使用php5.3+,使用了一些自定义的内容,不过都一看便知
比如常量ROOT、DIR_CACHE等
核心使用的有
diehere(输出json字符串,并die),err_a(组合错误信息),makedir(连续创建目录)
其余的都根据实际使用的情况来

终于debug完成了……新增one_key方法,一键完成输出,完美……
departments初次查询170ms
之后仅16ms,越复杂效果越好啊

高复杂测试get_users_complex.php
初次108.0 KB  985ms
第二次16ms,哈哈哈,
清空etag(未清空data)读取,接收数据125ms                        

1. [代码]DEF.inc.php    

	define('ROOT',dirname(__FILE__));

	define('CLS_SCACHER','/inc/SCACHER.cls.php');
	define('CLS_ECACHER','/inc/ECACHER.cls.php');

	define('DIR_CACHE','/cache/');	//用于缓存判断的目录


function run_sql($sql){
	static $db;
	if(!$db){
		$db=getdb();
	}
	return mysql_query($sql,$db);
}

function getdb(){
	static $mydb;
	if(!$mydb){
		$mydb=dbconnection();
	}
	return $mydb;
}

function dbconnection(&$var=0){
	
	if($var==0||!is_array($var)){$var=array();}
	if(!isset($var['dbhost']) || !is_string($var['dbhost'])){	$var['dbhost']=constant('DBHOST');}
	if(!isset($var['dbuser']) || !is_string($var['dbuser'])){	$var['dbuser']=constant('DBUSER');}
	if(!isset($var['dbpsw']) || !is_string($var['dbpsw'])){$var['dbpsw']=constant('DBPSW');}
	$db=mysql_connect($var['dbhost'],$var['dbuser'],$var['dbpsw']) or die();
	if(!$db){return 0;}
	mysql_select_db(constant('DBNAME'),$db) or die();//echo('db enter here');
	mysql_query("SET NAMES 'UTF8'");
	return $db;
}

function PR($v){
	if(isset($v)){
		echo(&#39;<pre class="brush:php;toolbar:false">&#39;);
		print_r($v);
		echo(&#39;
'); } } function rs_2_array($rs){ //this is a function used to make the code clear and less //i am tired to code same code to get the arry result //thought it is not much //redlz2500@2008-06-24 $t=array(); try { while($row=mysql_fetch_array($rs,MYSQL_ASSOC)){ $t[]=$row; } return $t; }catch (Exception $e) { } return $t; } /* * 功能:连续建目录 * $dir 目录字符串 */ function makedir($dir,$mode = '0777') { //notice: the $dir will not set the code style & //as maybe call by $str.$str1 //the var can not be reference if(!isset($dir)){return 0;} //echo('
**********intomakedir*************
'.$dir); $dir = str_replace( "\\", "/", $dir ); $mdir = ""; foreach( explode( "/", $dir ) as $val ) { $mdir .= $val."/"; if( $val == ".." || $val == "." ) continue; if( ! file_exists( $mdir ) ) { if(!@mkdir( $mdir, $mode )){ echo "创建目录 [".$mdir."]失败."; exit; } } } return true; }
로그인 후 복사

2. [代码]CLS_SCACHER

<?php
/*
//超级简单的文件缓存类,用于ECACHE的数据缓存支持
//使用ROOT.DIR_CACHE作为基本目录,下面再是path划分小目录,category和name组合为缓存文件的名称
//不包括时间有效期,若需使用时间有效判定,使用CLS_CACHER类
//属性配置调用scacher方法
//set($v)直接设置$v的值到缓存
//get()和del()无参数,含义自明
//主要用于CLS_ECACHER的底层支持
//redlz2500@20151022
*/
	
	class scacher{
		protected $fullpath=&#39;&#39;;
		protected $path=&#39;&#39;;	//在ROOT.DIR_CACHE目录下的,左右无目录分隔符
		protected $category=&#39;default&#39;;	//缓存下的分类
		protected $name=&#39;mycache&#39;;	//文件标识名称
		
		public function __construct($opt){
			$this->scacher($opt);
		}
		
		public function scacher($opt=[]){
			$flag=false;
			if($opt[&#39;category&#39;] && is_string($opt[&#39;category&#39;]) && ($this->category!=$opt[&#39;category&#39;]) ){
				$this->category=$opt[&#39;category&#39;];
				$flag=true;
			}
			if($opt[&#39;name&#39;] && is_string($opt[&#39;name&#39;]) && ($this->name!=$opt[&#39;name&#39;])){
				$this->name=$opt[&#39;name&#39;];
				$flag=true;
			}
			if($opt[&#39;path&#39;] && is_string($opt[&#39;path&#39;]) && ($this->pat!=$opt[&#39;path&#39;])){
				$this->path=$opt[&#39;path&#39;];
				$flag=true;
			}
			if($flag){
				if($this->path){
					$this->fullpath=ROOT.DIR_CACHE.$this->path.&#39;/&#39;;
				}else{
					$this->fullpath=ROOT.DIR_CACHE;
				}
				if(!file_exists($this->fullpath)){
					makedir($this->fullpath);
					if(!file_exists($this->fullpath)){
						throw new Exception(&#39;errSCACHER配置失败 当前调用参数:&#39;.$this->category.&#39;.&#39;.$this->name);
					}
				}
			}
		}
		
		public function set($v){
			$fp=fopen($this->fullpath . $this->category .&#39;.&#39;. $this->name,&#39;w&#39;);
			if (!fwrite($fp,$v)) {
				return [&#39;success&#39;=>false,&#39;error&#39;=>err_a(&#39;errSCACHER_1&#39;,&#39;数据写入失败,请稍后重试。<br/>重试无效请联系管理员。<br/>当前调用参数:&#39;.$this->category.&#39;.&#39;.$this->name)];
			}  
			@fclose($fp);
			return [&#39;success&#39;=>true];
		}
		public function get(){
			$f=$this->fullpath . $this->category .&#39;.&#39;. $this->name;
			if(file_exists($f)){
				$res=@file_get_contents($f);
				if(!$res){
					$res=&#39;&#39;;
				}
				return [&#39;success&#39;=>true,&#39;data&#39;=>$res];
			}else{
				return [&#39;success&#39;=>false,&#39;data&#39;=>&#39;&#39;,&#39;error&#39;=>err_a(&#39;errSCACHER_3&#39;,&#39;未找到缓存。<br/>当前调用参数:&#39;.$this->category.&#39;.&#39;.$this->name)];
			}
		}
		public function del(){
			$f=$this->fullpath . $this->category .&#39;.&#39;. $this->name;
			if(file_exists($f)){
				@unlink($f);
				if(file_exists($f)){
					return [&#39;success&#39;=>false,&#39;error&#39;=>err_a(&#39;errSCACHER_2&#39;,&#39;数据处理异常,请稍后重试。<br/>重试无效请联系管理员。<br/>当前调用参数:&#39;.$this->category.&#39;.&#39;.$this->name)];
				}
			}else{
				return [&#39;success&#39;=>true];
			}
		}
	}
?>
로그인 후 복사

3. [代码]CLS_ECACHER

<?php
/*
//基于CLS_CACHER的缓存机制,包括etag参数以及其余的数据,主要用于单个的json数据缓存
//主要目的为在服务器端给json方式做缓存,模式如下:
//核心的detail缓存由后台互动生成(也可以由前台生成,方法摆在这里自己组合)
//1、查询端query.php
//	调用etag_chk,相同则 发送304header(默认允许)
//		不同则调用data_get方法,取出缓存,如果取出缓存失败,则前台处理,不重新生成缓存(也可以生成,但是需重新包括缓存生成方法)
//2、数据生成页面trigger.php
//	触发数据重新生成机制 ,生成新的缓存,并更新etag信息,这样做在触发频繁的情况下可能引起大量无必要的数据库操作,
//可在此时修改触发方式,或者触发的时候仅清空数据,但是并不重新生成缓存,而在前台实际调用的时候才执行缓存生成操作
//A、或者是在查询段负责生成数据,触发端负责清空缓存
//	ecacher重设参数
//	mode_etag mode_data在两种模式下切换,内部方法
//	etag_chk	检查浏览器是否一致,一致的话 发送304(默认允许)
//	etag_create	生成新的etag并缓存
//	data_get	获取缓存的data
//	data_create	调用外部定义的方法以及参数生成缓存并重设etag,注意,虽然重设了etag,但是并不会重新发送200
//	clear	清空数据,传入数组
//第一次生成数据的时候可能不正确,未处理	已经解决redlz2500@20151022
//v1.1新增one_key方法
//v1.2增加catch-control输出。某个页面一直无法输出304,检查服务器返回catch-control:no-catch……查不出原因,直接重写了……
//v1.3增加force参数,用于强制输出catch-control控制,默认false,为true强制输出自己的catch-control,以避免和php自己的session_cache_limiter冲突
//redlz2500@20151022
*/

	define(&#39;DEF_ECACHE_PERFECT&#39;,&#39;0001&#39;);	//浏览器发送了匹配的etag,完美,返回304
	define(&#39;DEF_ECACHE_BROWSER_NULL&#39;,&#39;0010&#39;);	//浏览器未发送etag
	define(&#39;DEF_ECACHE_ETAG_NULL&#39;,&#39;0100&#39;);	//本地的etag记录为空(可能是数据真空期)
	define(&#39;DEF_ECACHE_ETAG_CREATED&#39;,&#39;1000&#39;);//etag成功生成

	require_once(ROOT.CLS_SCACHER);//使用scacher类
	
	class ecacher{
		protected $path=&#39;&#39;;
		protected $category=&#39;default&#39;;	//当前类别的分类
		protected $name=&#39;myname&#39;;		//模板名称
		//以上三个是scacher类的定义,方式与ecacher相同,缓存位置由ecacher来控制
		protected $force_cache=false;
		protected $auto_send_etag_header=true;	//是否自动发送header信息

		protected $create_fn=&#39;&#39;;	//没有数据的时候生成数据的回调函数,返回数据由data_create处理,仅支持字符串
		protected $create_par;		//生成数据的时候需要传送的参数,按参数先后顺序组合为array传送,不是数组则自动将其转换为数组
		
		protected $scacher;
		
		public function __construct($opt){
			$this->scacher=new scacher([]);		//scacher实例,路径由scacher来控制
			$this->ecacher($opt);
		}
		
		public function __destruct(){
			
		}
		
		function ecacher($opt){
			if(is_array($opt)){
				if($opt[&#39;force_cache&#39;]){
					$this->force_cache=true;
				}else{
					if(isset($opt[&#39;force_cache&#39;])){
						$this->force_cache=false;
					}
				}
				if($opt[&#39;path&#39;] && is_string($opt[&#39;path&#39;])){
					$this->path=$opt[&#39;path&#39;];
				}
				if($opt[&#39;category&#39;] && is_string($opt[&#39;category&#39;])){
					$this->category=$opt[&#39;category&#39;];
				}
				if($opt[&#39;name&#39;] && is_string($opt[&#39;name&#39;])){
					$this->name=$opt[&#39;name&#39;];
				}
				if(isset($opt[&#39;auto_send_etag_header&#39;])){
					$this->auto_send_etag_header=$opt[&#39;auto_send_etag_header&#39;];
				}
				if($opt[&#39;create_fn&#39;] && is_string($opt[&#39;create_fn&#39;])){
					$this->create_fn=$opt[&#39;create_fn&#39;];
				}
				if($opt[&#39;create_par&#39;]){
					if(is_array($opt[&#39;create_par&#39;])){
						$this->create_par=$opt[&#39;create_par&#39;];
					}else{
						$this->create_par=[$opt[&#39;create_par&#39;]];
					}
				}else{
					$this->create_par=[];
				}
				$this->scacher->scacher($opt);//更新的数据写入(好吧,其实并没有什么卵用)(好吧,可以提前判断缓存路径有没有效)
			}
		}
		
		private function mode_etag(){
			$this->scacher->scacher([&#39;name&#39;=>$this->name.&#39;.etag&#39;]);
		}
		private function mode_data(){
			$this->scacher->scacher([&#39;name&#39;=>$this->name.&#39;.&#39;]);
		}
		public function etag_chk(){
			$this->mode_etag();//设置etag模式
			$etag=$this->scacher->get();
			echo_debug(&#39;test etag&#39;);
			echo_debug($etag);
			if($etag[&#39;success&#39;]){
				$etag=$etag[&#39;data&#39;];
			}else{
				return $etag;
			}
			$s_etag=$_SERVER[&#39;HTTP_IF_NONE_MATCH&#39;];
			echo_debug(&#39;etag from browse&#39;);
			echo_debug($s_etag);
			if($etag){
				if($s_etag==$etag){
					if($this->auto_send_etag_header){
						if($this->force_cache){
							header(&#39;Cache-Control: max-age=0&#39;);
							header(&#39;Expires: &#39;.gmdate(&#39;D, d M Y H:i:s&#39;, time() + SERVER_TIME_SHIFT + 10 ) . &#39; GMT&#39; );
						}
						header(&#39;Etag:&#39;.$etag,true,304);
						die();//必须die,否则还会继续执行下去。
					}else{
						return [	&#39;etag&#39;=>$etag,	&#39;statue&#39;=>DEF_ECACHE_PERFECT	];
					}
				}else{
					if($this->auto_send_etag_header){
						if($this->force_cache){
							header(&#39;Cache-Control: max-age=0&#39;);
							header(&#39;Expires: &#39;.gmdate(&#39;D, d M Y H:i:s&#39;, time() + SERVER_TIME_SHIFT + 10 ) . &#39; GMT&#39; );
						}
						header(&#39;Etag:&#39;.$etag);
					}
					return [	&#39;etag&#39;=>$etag,	&#39;statue&#39;=>DEF_ECACHE_BROWSER_NULL	];
				}
			}else{
				return [
					&#39;etag&#39;=>&#39;&#39;,
					&#39;statue&#39;=>DEF_ECACHE_ETAG_NULL
				];
			}
		}
		
		public function etag_create($auto=false){
			$etag=md5($this->category.&#39;:&#39;.$this->name.&#39;:&#39;.time().&#39;:&#39;.ranstr());
			$this->mode_etag();
			$this->scacher->set($etag);
			if($auto){
				if($this->force_cache){
					header(&#39;Cache-Control: max-age=0&#39;);
					header(&#39;Expires: &#39;.gmdate(&#39;D, d M Y H:i:s&#39;, time() + SERVER_TIME_SHIFT + 10 ) . &#39; GMT&#39; );
				}
				header(&#39;Etag:&#39;.$etag);
			}
			echo_debug(&#39;etag create finish:&#39;.$etag);
			return [
				&#39;success&#39;=>true,
				&#39;etag&#39;=>$etag,
				&#39;status&#39;=>DEF_ECACHE_ETAG_CREATED
			];
		}
		
		public function data_get(){
			//PR(&#39;begin get data&#39;);BR();
			$this->mode_data();
			$data=$this->scacher->get();
			if($data[&#39;success&#39;]){
				echo_debug(&#39;orgin data is:&#39;);
				echo_debug($data[&#39;data&#39;]);
				$data[&#39;data&#39;]=unserialize($data[&#39;data&#39;]);
			}else{
				echo_debug(&#39;not success:&#39;);
				echo_debug($data);
				$data[&#39;data&#39;]=&#39;&#39;;
			}
			echo_debug();
			echo_debug(&#39;the data is:&#39;);
			echo_debug($data);
			return $data;
		}
		public function data_create($auto_etag=false){
			if(!$this->create_fn){
				throw new Exception(&#39;<ECACHER>未传递数据生成函数<br/>当前参数:&#39;.$this->category.&#39;.&#39;.$this->name);		//这样的错误时不允许的,因此直接抛出错误
				die();
			}
			$data=call_user_func_array($this->create_fn,$this->create_par);
			//生成数据的处理
			if($data===false){
				throw new Exception(&#39;<ECACHER>生成数据失败<br/>当前参数:&#39;.$this->category.&#39;.&#39;.$this->name);		//无法,只有不返回false了
				die();
			}
			//PR($data);
			$s_data=serialize($data);
			$this->mode_data();
			$res=$this->scacher->set($s_data);
			if(!$res[&#39;success&#39;]){	return $res;	}
			if($auto_etag){
				$res=$this->etag_create();
				if(!$res[&#39;success&#39;]){	return $res;	}
			}
			return [&#39;success&#39;=>true,&#39;data&#39;=>$data];
		}
		
		public function clear($p=[&#39;etag&#39;,&#39;data&#39;]){
			if(in_array(&#39;both&#39;,$p)){
				$p=[&#39;etag&#39;,&#39;data&#39;];
			}
			if(in_array(&#39;etag&#39;,$p)){
				$this->mode_data();
				$res=$this->scacher->del();
				if(!$res[&#39;success&#39;]){	return $res;	}
			}
			if(in_array(&#39;etag&#39;,$p)){
				$this->mode_etag();
				$res=$this->scacher->del();
				if(!$res[&#39;success&#39;]){	return $res;	}
			}
			return [&#39;success&#39;=>true];
		}
		
		public function one_key(){
			$r=$this->etag_chk();
			if(!$r[&#39;etag&#39;]){
				echo_debug(&#39;the etag is null,should be rebuild&#39;);
				echo_debug($r);
				$this->etag_create(&#39;auto&#39;);
			}
			$res=$this->data_get();
			if($res[&#39;success&#39;]){
				//PR($res);
				if($res[&#39;data&#39;]){
					diehere($res);
				}
			}
			echo_debug(&#39;recreate data&#39;);
			
			$data=$this->data_create();
			diehere($data);
		}
	}
?>
로그인 후 복사

4. [代码]get_departments.php

<?php
//实在受不了每次的数据的读取咯,所以按照以下的方式进行处理:
//对于部门,因为内容不算很多,120多个的样子,有效部门90个的样子,因此将其一次性进行处理,使用这个东西来创造,使用缓存机制
//如果数据没有变化的,就读取缓存,如果有变化的,就发送数据
//redlz2500@20151022
	define(&#39;IN_SERVER&#39;,1);
	require(&#39;../../../DEF.inc.php&#39;);
	require(ROOT.CLS_ECACHER);
	
	//define(&#39;ECHO_DEBUG&#39;,0);
	//define(&#39;ECHO_DEBUG&#39;,1);
	
	$e=new ecacher([
		&#39;create_fn&#39;=>&#39;get_departments&#39;,
		&#39;path&#39;=>&#39;json&#39;,&#39;category&#39;=>&#39;common&#39;,&#39;name&#39;=>&#39;department&#39;
	]);
	
	$e->one_key();
	
	die();
function get_departments(){
	$sql=&#39;select `depid` as `id`,`name`,`father`,`departcode` as `code` from `department` where `father` !=0&#39;;
	
	$rs=run_sql($sql);
	$data=[];
	require_once(ROOT.INC_MAIL);
	while($row=mysql_geta($rs)){
		$address=get_dep_mail_address($row[&#39;id&#39;]);
		$fullname=explode(&#39;.&#39;,$address);
		$fullname=array_reverse($fullname);
		$fullname=implode(&#39;.&#39;,$fullname);
		$row[&#39;fullname&#39;]=$fullname;
		$data[]=$row;
	}
	return $data;
}
?>
로그인 후 복사

5. [代码]get_users.php

<?php
//本来想一次性全部读取,想到数量还是有点儿大,还是按照部门来读取好了
//redlz2500@20151022
	define(&#39;IN_SERVER&#39;,1);
	require(&#39;../../../DEF.inc.php&#39;);
	require(ROOT.CLS_ECACHER);
	
	$par=$_POST;
	$par=$_GET;
	$res[&#39;success&#39;]=false;
	if(!$par[&#39;depid&#39;]){
		$res[&#39;error&#39;]=err_a(&#39;errU038&#39;,&#39;参数缺失&#39;);
		diehere($res);
	}
	if(!isDecimalNumber($par[&#39;depid&#39;])){
		$res[&#39;error&#39;]=err_a(&#39;errU039&#39;,&#39;参数错误&#39;);
		diehere($res);
	}
	$e=new ecacher([
		&#39;create_fn&#39;=>&#39;get_users&#39;,
		&#39;create_par&#39;=>$par[&#39;depid&#39;],
		&#39;path&#39;=>&#39;json&#39;,&#39;category&#39;=>&#39;common&#39;,&#39;name&#39;=>&#39;users_in_&#39;.$par[&#39;depid&#39;]]);
	
	$e->one_key();
	
function get_users($depid){
	$sql=&#39;select `uid`,`name`,`login`,`depid` from `user` where `register` = 1 and `depid` = &#39;.$depid;
	$rs=run_sql($sql);
	$rs=rs_2_array($rs);
	return $rs;
}

?>
로그인 후 복사

6. [代码]get_users_complex.php

<?php
//本来想一次性全部读取,想到数量还是有点儿大,还是按照部门来读取好了
//redlz2500@20151022
	define(&#39;IN_SERVER&#39;,1);
	require(&#39;../../../DEF.inc.php&#39;);
	require(ROOT.CLS_ECACHER);
	
	$res[&#39;success&#39;]=false;

	$e=new ecacher([
		&#39;create_fn&#39;=>&#39;get_users&#39;,
		&#39;create_par&#39;=>$par[&#39;depid&#39;],
		&#39;path&#39;=>&#39;json&#39;,&#39;category&#39;=>&#39;common&#39;,&#39;name&#39;=>&#39;users_all&#39;]);
	
	$e->one_key();
	
function get_users(){
	$sql=&#39;select `uid`,`name`,`login`,`depid` from `user` where `register` = 1 &#39;;
	$rs=run_sql($sql);
	require_once(ROOT.INC_MAIL);
	$data=[];
	while($row=mysql_geta($rs)){
		$addr=_get_user_mail_address($row[&#39;login&#39;]);
		$row[&#39;addr&#39;]=$addr;
		$data[]=$row;
	}
	return $data;
}

?>
로그인 후 복사

                   

                   

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

CakePHP 프로젝트 구성 CakePHP 프로젝트 구성 Sep 10, 2024 pm 05:25 PM

이번 장에서는 CakePHP의 환경 변수, 일반 구성, 데이터베이스 구성, 이메일 구성에 대해 알아봅니다.

Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Dec 24, 2024 pm 04:42 PM

PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

CakePHP 날짜 및 시간 CakePHP 날짜 및 시간 Sep 10, 2024 pm 05:27 PM

cakephp4에서 날짜와 시간을 다루기 위해 사용 가능한 FrozenTime 클래스를 활용하겠습니다.

CakePHP 파일 업로드 CakePHP 파일 업로드 Sep 10, 2024 pm 05:27 PM

파일 업로드 작업을 위해 양식 도우미를 사용할 것입니다. 다음은 파일 업로드의 예입니다.

CakePHP 토론 CakePHP 토론 Sep 10, 2024 pm 05:28 PM

CakePHP는 PHP용 오픈 소스 프레임워크입니다. 이는 애플리케이션을 훨씬 쉽게 개발, 배포 및 유지 관리할 수 있도록 하기 위한 것입니다. CakePHP는 강력하고 이해하기 쉬운 MVC와 유사한 아키텍처를 기반으로 합니다. 모델, 뷰 및 컨트롤러 gu

CakePHP 라우팅 CakePHP 라우팅 Sep 10, 2024 pm 05:25 PM

이번 장에서는 라우팅과 관련된 다음과 같은 주제를 학습하겠습니다.

CakePHP 데이터베이스 작업 CakePHP 데이터베이스 작업 Sep 10, 2024 pm 05:25 PM

CakePHP에서 데이터베이스 작업은 매우 쉽습니다. 이번 장에서는 CRUD(생성, 읽기, 업데이트, 삭제) 작업을 이해하겠습니다.

CakePHP 유효성 검사기 만들기 CakePHP 유효성 검사기 만들기 Sep 10, 2024 pm 05:26 PM

컨트롤러에 다음 두 줄을 추가하면 유효성 검사기를 만들 수 있습니다.

See all articles