├── LICENSE ├── README.md ├── dom-xss ├── README.md └── index.php ├── local-file-inclusion ├── README.md ├── index.php ├── morpheus_lfi.jpg └── preview.php ├── parameter-tampering ├── README.md ├── index.php └── ticket_booking.php ├── reflected-xss ├── README.md └── index.php ├── remote-code-execution ├── README.md └── index.php ├── remote-file-inclusion ├── README.md ├── index.php ├── preview.php └── rfi.jpg ├── unvalidated-redirects ├── README.md ├── index.php ├── redirect.html └── unvalidated-redirects.jpg └── utils ├── db_init.php └── medoo.min.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Siddharth Goel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Attacks 2 | 3 | ### What is this repo? 4 | This repository is for educational purpose which showcases some of the famous web related attacks through source code and explanatory README files. Efforts are made to explain the attack with extremely simple examples so that it gives a clear picture of vulnerability. 5 | 6 | ### Which all attacks does it cover? 7 | - DOM Based XSS 8 | - Local file inclusion 9 | - Parameter tampering 10 | - Reflected XSS 11 | - Remote code execution 12 | - Remote file inclusion 13 | - Unvalidated redirects and forwards 14 | 15 | ### Can I contribute to this project? 16 | Absolutely !! Contributions are welcomed through Pull Requests. But a couple of points before you send your contribution :- 17 | - The coding style, directory structure, README.md and all other formats should match to the existing style of repository. 18 | 19 | ### Disclaimer 20 | This education is for educational purpose only. Developers and contributers of this project will not be responsible for any damage caused directly or indirectly through this project. 21 | 22 | -------------------------------------------------------------------------------- /dom-xss/README.md: -------------------------------------------------------------------------------- 1 | # DOM Based XSS 2 | 3 | ### What is it? 4 | This is a special kind of XSS attack in malicious code/script in not injected into the page/application. Instead it is a client side attack in which the malicious code/script runs on the client side on the page loaded by the server and server never gets to know it. The fact that server never gets to know about 5 | this makes this attack more dangerous. Currently a major section of the websites are affected by this vulnerability. 6 | 7 | ### Diagram 8 | Need to add diagram !! 9 | 10 | ### Attack vector 11 | Need to fill info here !! 12 | 13 | ### How to Prevent it? 14 | - Safe coding is the only elegant way to prevent this attack. Avoid the use of following HTML rendering methods :- 15 | - element.innerHTML 16 | - element.outerHTML 17 | - document.write() 18 | - document.writeln() 19 | - Do not pass the user input or any untrusted source of data to eval(). 20 | 21 | #### Sources 22 | - https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet 23 | -------------------------------------------------------------------------------- /dom-xss/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DOM XSS 6 | 7 | 8 | 9 | 14 | 15 |

Hello App !!

16 | Enter your name: 17 |
18 | 19 | 20 |
21 | 22 | 23 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /local-file-inclusion/README.md: -------------------------------------------------------------------------------- 1 | # Local file inclusion 2 | 3 | ### What is it? 4 | This bug allows an attacker to expose a file existing locally on the server where the application is hosted. Main reason for this vulnerability is using usr input data for including of a file. [Owasp] says that, it can also lead to: 5 | - Code execution on the web server 6 | - Code execution on the client-side such as JavaScript which can lead to other attacks such as cross site scripting (XSS) 7 | - Denial of Service (DoS) 8 | - Sensitive Information Disclosure 9 | 10 | ### Attack vector 11 | 12 | 13 | ### How to prevent it? 14 | - Best way is by NOT using the input parameter from client/user to include a file. 15 | - Input validation is another approach. But this is not the advisable approach because there may be corner cases which might be missed in the validation. 16 | 17 | [owasp]:https://www.owasp.org/index.php/Testing_for_Local_File_Inclusion 18 | -------------------------------------------------------------------------------- /local-file-inclusion/index.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /local-file-inclusion/morpheus_lfi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharthgoel88/web-attacks/e3f107a684c7f894ce639191668e15340f4260ad/local-file-inclusion/morpheus_lfi.jpg -------------------------------------------------------------------------------- /local-file-inclusion/preview.php: -------------------------------------------------------------------------------- 1 | ============================= "; 7 | echo "
Below page is the included one
"; 8 | echo "
=============================
"; 9 | echo "
"; 10 | include("$file"); 11 | } 12 | else 13 | { 14 | echo ""; 15 | echo "
"; 16 | echo ""; 17 | 18 | } 19 | ?> 20 | -------------------------------------------------------------------------------- /parameter-tampering/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Parameter Tampering 2 | 3 | ### What is it? 4 | This vulnerability allows tampering of the parameters which are sent between client and server for the attacker's advantage. In this bug, user input validation / restriction only happens (if happens) on the client side and server side validation is missing. This allows the attacker to manipulate the data and send the tampered data to the server. 5 | 6 | ### Attack vector 7 | 8 | 9 | ### How to prevent it? 10 | - Only way to prevent it is by doing a server side validation of the input. 11 | -------------------------------------------------------------------------------- /parameter-tampering/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTTP Parameter Tampering 6 | 15 | 16 | 17 | 18 |
19 |

Hackathon ticket booking

20 |
 Each ticket costs 15 $ 
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 42 | 43 | 44 | 47 | 51 | 52 |
Name
Email
Number of tickets 34 | 41 |
45 | Total Amount 46 | 48 | 49 |
15 $
50 |
53 | 54 |
55 | 56 |




57 | 58 |

People who already bought hackathon tickets:

59 | 74 |
75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /parameter-tampering/ticket_booking.php: -------------------------------------------------------------------------------- 1 | " . $name . " " . $email . " " . $tickets . " " . $amount); 7 | try { 8 | $db->insert('parameter_tampering', [ 9 | 'name' => $name , 10 | 'email' => $email , 11 | 'number_of_tickets' => $tickets, 12 | 'amount' => $amount 13 | ]); 14 | } catch(Exception $e) { 15 | error_log('Message: ' .$e->getMessage()); 16 | } 17 | } 18 | 19 | function list_all_hackers() { 20 | $db = get_db_connection(); 21 | $hackers = $db->select('parameter_tampering', '*'); 22 | $output = "
";
23 | 		foreach($hackers as $hacker) {
24 | 			$output .= "";
28 | 		}
29 | 		$output .= "
" .$hacker["id"] . ". " . $hacker["name"] . " booked " 25 | . $hacker["number_of_tickets"] . " and paid " 26 | . $hacker["amount"] . "$ . (Email: " 27 | . $hacker["email"] . " )
"; 30 | return $output; 31 | } 32 | 33 | ?> 34 | -------------------------------------------------------------------------------- /reflected-xss/README.md: -------------------------------------------------------------------------------- 1 | # Reflected XSS 2 | 3 | ### What is it? 4 | As the name suggests, in this attack the attack payload goes to the server through the victim's browser as request and in response returns a page which contains the malicious script. The attack payload hence runs of the victim's browser and sends sensitive information (mostly cookies) to the attacker. 5 | 6 | The attacker can be very innovative in sending that malicious link to the victim. So of the famous channels are phishing e-mails, advertisements on malicious 7 | websites, etc. 8 | 9 | ### Diagram 10 | Need to all diagram !! 11 | 12 | ### Attack vector 13 | Need to fill info here !! 14 | 15 | ### How to Prevent it? 16 | - Sanitize input and output. 17 | - XSS auditor of different browser try to detect it stop. But no browser does it full-proof. Check out [this]. 18 | - The most common use-case of XSS is to steal cookie. You can make your cookies as [HTTP-ONLY] which will avoid Javascript from access the cookie. 19 | 20 | [this]:http://blog.securitee.org/?p=37 21 | [HTTP-ONLY]:https://www.owasp.org/index.php/HttpOnly 22 | -------------------------------------------------------------------------------- /reflected-xss/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Reflected XSS 6 | 7 | 8 | 9 | 14 | 15 |

Hello App !!

16 | Enter your name: 17 |
18 | 19 | 20 |
21 | 22 | 23 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /remote-code-execution/README.md: -------------------------------------------------------------------------------- 1 | # Remote Code Execution / Command Injection 2 | 3 | ### What is it? 4 | This bug allows an attacker to run code or commands on the server on which the application is hosted. In most of the cases the reason for this vulnerability is use of unvalidated input (forms, cookie, HTTP header, etc.) from user to execute some command on the system shell on server-side. 5 | 6 | ### Attack vector 7 | 8 | 9 | ### How to prevent it? 10 | - Special care should be taken for the parameters passed to system commands. Ideally user input should not be passed to system command. 11 | - If one needs to pass a user input to system command the data validation needs to be done. Also remember in security one should follow the approach of whitelisting instead of blacklisting. 12 | 13 | ##### Sources : 14 | https://www.owasp.org/index.php/Command_Injection 15 | https://www.owasp.org/index.php/PHP_Top_5 16 | -------------------------------------------------------------------------------- /remote-code-execution/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Traceroute application 6 | 7 | 8 | 9 |

Fancy traceroute app


10 | Enter website address/ip : 11 |
12 | 13 | 14 |
15 | 16 | " . $output . ""; 21 | } else { 22 | echo "
You need to enter a valid ip !!
"; 23 | } 24 | ?> 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /remote-file-inclusion/README.md: -------------------------------------------------------------------------------- 1 | # Remote file inclusion 2 | 3 | ### What is it? 4 | This bug is conceptually very similar to Local file inclusion. In this bug an attacker can include a remote file into an application which was actually not the intention of the application. Main reason for this vulnerability is using user input data for including of a file. 5 | 6 | RFI might result to :- 7 | - Cookie and sensitive information stealing 8 | - Phishing attack and stealing of user credentials 9 | 10 | ### Attack vector 11 | 12 | 13 | ### How to prevent it? 14 | - Best way is by NOT using the input parameter from client/user to include a file. 15 | - Input validation is another approach. Whitlisting approach should be taken instead of blacklisting. 16 | 17 | -------------------------------------------------------------------------------- /remote-file-inclusion/index.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /remote-file-inclusion/preview.php: -------------------------------------------------------------------------------- 1 | =============================
"; 12 | echo "
Below page is the included one
"; 13 | echo "
=============================
"; 14 | echo "
"; 15 | include("http://" . $url); 16 | } 17 | else 18 | { 19 | echo ""; 20 | echo "
"; 21 | echo ""; 22 | 23 | } 24 | ?> 25 | -------------------------------------------------------------------------------- /remote-file-inclusion/rfi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharthgoel88/web-attacks/e3f107a684c7f894ce639191668e15340f4260ad/remote-file-inclusion/rfi.jpg -------------------------------------------------------------------------------- /unvalidated-redirects/README.md: -------------------------------------------------------------------------------- 1 | # Unvalidated redirects and forwards 2 | 3 | ### What is it? 4 | [OWASP] says that it is linking to a destination without proper validation that leads to unauthorized page. Attacker might redirect victim to phishing webpage and steal the credentials. 5 | 6 | ### Attack vector 7 | Need to fill info here !! 8 | 9 | ### How to Prevent it? 10 | - From security perspective, redirects should not be used in websites. 11 | - If redirects are necessary, then try providing the direct links instead of calculating the destination. 12 | - If direct links also could not be used, then do the manipulation on server-side with proper validation. 13 | - Users of a website should pay attention to the URL before clicking. 14 | 15 | ### Sources 16 | https://www.owasp.org/index.php/Top_10_2013-Top_10 17 | http://www.slideshare.net/ShaneStanley/a10-unvalidated-redirects 18 | https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards 19 | 20 | [OWASP]:https://www.owasp.org/index.php/Top_10_2013-Top_10 21 | 22 | -------------------------------------------------------------------------------- /unvalidated-redirects/index.php: -------------------------------------------------------------------------------- 1 | "; 3 | 4 | if(isset($_GET['redirect'])){ 5 | echo "Will be redirecting in 5 seconds"; 6 | $redirect_url = $_GET['redirect']; 7 | header("refresh: 5; url=" . $redirect_url ); 8 | } 9 | ?> 10 | -------------------------------------------------------------------------------- /unvalidated-redirects/redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unvalidated Redirects 6 | 7 | 8 | 9 |
10 | Unvalidated redirects 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /unvalidated-redirects/unvalidated-redirects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharthgoel88/web-attacks/e3f107a684c7f894ce639191668e15340f4260ad/unvalidated-redirects/unvalidated-redirects.jpg -------------------------------------------------------------------------------- /utils/db_init.php: -------------------------------------------------------------------------------- 1 | 'mysql', 8 | 'database_name' => 'web_attacks', 9 | 'server' => 'localhost', 10 | 'username' => 'webattacker', 11 | 'password' => 'pass@123', 12 | 'charset' => 'utf8' 13 | ]); 14 | return $database; 15 | } 16 | 17 | ?> 18 | -------------------------------------------------------------------------------- /utils/medoo.min.php: -------------------------------------------------------------------------------- 1 | database_type)=='sqlite'){$this->database_file=$options;}else {$this->database_name=$options;}}elseif(is_array($options)){foreach($options as $option=>$value){$this->$option=$value;}}if(isset($this->port)&&is_int($this->port*1)){$port=$this->port;}$type=strtolower($this->database_type);$is_port=isset($port);switch($type){case 'mariadb':$type='mysql';case 'mysql':if($this->socket){$dsn=$type.':unix_socket='.$this->socket.';dbname='.$this->database_name;}else {$dsn=$type.':host='.$this->server.($is_port?';port='.$port:'').';dbname='.$this->database_name;}$commands[]='SET SQL_MODE=ANSI_QUOTES';break;case 'pgsql':$dsn=$type.':host='.$this->server.($is_port?';port='.$port:'').';dbname='.$this->database_name;break;case 'sybase':$dsn='dblib:host='.$this->server.($is_port?':'.$port:'').';dbname='.$this->database_name;break;case 'oracle':$dbname=$this->server?'//'.$this->server.($is_port?':'.$port:':1521').'/'.$this->database_name:$this->database_name;$dsn='oci:dbname='.$dbname.($this->charset?';charset='.$this->charset:'');break;case 'mssql':$dsn=strstr(PHP_OS,'WIN')?'sqlsrv:server='.$this->server.($is_port?','.$port:'').';database='.$this->database_name:'dblib:host='.$this->server.($is_port?':'.$port:'').';dbname='.$this->database_name;$commands[]='SET QUOTED_IDENTIFIER ON';break;case 'sqlite':$dsn=$type.':'.$this->database_file;$this->username=null;$this->password=null;break;}if(in_array($type,explode(' ','mariadb mysql pgsql sybase mssql'))&&$this->charset){$commands[]="SET NAMES '".$this->charset."'";}$this->pdo=new PDO($dsn,$this->username,$this->password,$this->option);foreach($commands as $value){$this->pdo->exec($value);}}catch(PDOException$e){ throw new Exception($e->getMessage());}} public function query($query){if($this->debug_mode){echo $query;$this->debug_mode=false;return false;}array_push($this->logs,$query);return $this->pdo->query($query);} public function exec($query){if($this->debug_mode){echo $query;$this->debug_mode=false;return false;}array_push($this->logs,$query);return $this->pdo->exec($query);} public function quote($string){return $this->pdo->quote($string);} protected function column_quote($string){return '"'.str_replace('.','"."',preg_replace('/(^#|\(JSON\))/','',$string)).'"';} protected function column_push($columns){if($columns=='*'){return $columns;}if(is_string($columns)){$columns=array($columns);}$stack=array();foreach($columns as $key=>$value){preg_match('/([a-zA-Z0-9_\-\.]*)\s*\(([a-zA-Z0-9_\-]*)\)/i',$value,$match);if(isset($match[1],$match[2])){array_push($stack,$this->column_quote($match[1]).' AS '.$this->column_quote($match[2]));}else {array_push($stack,$this->column_quote($value));}}return implode($stack,',');} protected function array_quote($array){$temp=array();foreach($array as $value){$temp[]=is_int($value)?$value:$this->pdo->quote($value);}return implode($temp,',');} protected function inner_conjunct($data,$conjunctor,$outer_conjunctor){$haystack=array();foreach($data as $value){$haystack[]='('.$this->data_implode($value,$conjunctor).')';}return implode($outer_conjunctor.' ',$haystack);} protected function fn_quote($column,$string){return (strpos($column,'#')===0&&preg_match('/^[A-Z0-9\_]*\([^)]*\)$/',$string))?$string:$this->quote($string);} protected function data_implode($data,$conjunctor,$outer_conjunctor=null){$wheres=array();foreach($data as $key=>$value){$type=gettype($value);if(preg_match("/^(AND|OR)(\s+#.*)?$/i",$key,$relation_match)&&$type=='array'){$wheres[]=0!==count(array_diff_key($value,array_keys(array_keys($value))))?'('.$this->data_implode($value,' '.$relation_match[1]).')':'('.$this->inner_conjunct($value,' '.$relation_match[1],$conjunctor).')';}else {preg_match('/(#?)([\w\.]+)(\[(\>|\>\=|\<|\<\=|\!|\<\>|\>\<|\!?~)\])?/i',$key,$match);$column=$this->column_quote($match[2]);if(isset($match[4])){$operator=$match[4];if($operator=='!'){switch($type){case 'NULL':$wheres[]=$column.' IS NOT NULL';break;case 'array':$wheres[]=$column.' NOT IN ('.$this->array_quote($value).')';break;case 'integer':case 'double':$wheres[]=$column.' != '.$value;break;case 'boolean':$wheres[]=$column.' != '.($value?'1':'0');break;case 'string':$wheres[]=$column.' != '.$this->fn_quote($key,$value);break;}}if($operator=='<>'||$operator=='><'){if($type=='array'){if($operator=='><'){$column.=' NOT';}if(is_numeric($value[0])&&is_numeric($value[1])){$wheres[]='('.$column.' BETWEEN '.$value[0].' AND '.$value[1].')';}else {$wheres[]='('.$column.' BETWEEN '.$this->quote($value[0]).' AND '.$this->quote($value[1]).')';}}}if($operator=='~'||$operator=='!~'){if($type=='string'){$value=array($value);}if(!empty($value)){$like_clauses=array();foreach($value as $item){if($operator=='!~'){$column.=' NOT';}if(preg_match('/^(?!%).+(?fn_quote($key,$item);}$wheres[]=implode(' OR ',$like_clauses);}}if(in_array($operator,array('>','>=','<','<='))){if(is_numeric($value)){$wheres[]=$column.' '.$operator.' '.$value;}elseif(strpos($key,'#')===0){$wheres[]=$column.' '.$operator.' '.$this->fn_quote($key,$value);}else {$wheres[]=$column.' '.$operator.' '.$this->quote($value);}}}else {switch($type){case 'NULL':$wheres[]=$column.' IS NULL';break;case 'array':$wheres[]=$column.' IN ('.$this->array_quote($value).')';break;case 'integer':case 'double':$wheres[]=$column.' = '.$value;break;case 'boolean':$wheres[]=$column.' = '.($value?'1':'0');break;case 'string':$wheres[]=$column.' = '.$this->fn_quote($key,$value);break;}}}}return implode($conjunctor.' ',$wheres);} protected function where_clause($where){$where_clause='';if(is_array($where)){$where_keys=array_keys($where);$where_AND=preg_grep("/^AND\s*#?$/i",$where_keys);$where_OR=preg_grep("/^OR\s*#?$/i",$where_keys);$single_condition=array_diff_key($where,array_flip(explode(' ','AND OR GROUP ORDER HAVING LIMIT LIKE MATCH')));if($single_condition!=array()){$where_clause=' WHERE '.$this->data_implode($single_condition,'');}if(!empty($where_AND)){$value=array_values($where_AND);$where_clause=' WHERE '.$this->data_implode($where[$value[0]],' AND');}if(!empty($where_OR)){$value=array_values($where_OR);$where_clause=' WHERE '.$this->data_implode($where[$value[0]],' OR');}if(isset($where['MATCH'])){$MATCH=$where['MATCH'];if(is_array($MATCH)&&isset($MATCH['columns'],$MATCH['keyword'])){$where_clause.=($where_clause!=''?' AND ':' WHERE ').' MATCH ("'.str_replace('.','"."',implode($MATCH['columns'],'", "')).'") AGAINST ('.$this->quote($MATCH['keyword']).')';}}if(isset($where['GROUP'])){$where_clause.=' GROUP BY '.$this->column_quote($where['GROUP']);if(isset($where['HAVING'])){$where_clause.=' HAVING '.$this->data_implode($where['HAVING'],' AND');}}if(isset($where['ORDER'])){$rsort='/(^[a-zA-Z0-9_\-\.]*)(\s*(DESC|ASC))?/';$ORDER=$where['ORDER'];if(is_array($ORDER)){if(isset($ORDER[1])&&is_array($ORDER[1])){$where_clause.=' ORDER BY FIELD('.$this->column_quote($ORDER[0]).', '.$this->array_quote($ORDER[1]).')';}else {$stack=array();foreach($ORDER as $column){preg_match($rsort,$column,$order_match);array_push($stack,'"'.str_replace('.','"."',$order_match[1]).'"'.(isset($order_match[3])?' '.$order_match[3]:''));}$where_clause.=' ORDER BY '.implode($stack,',');}}else {preg_match($rsort,$ORDER,$order_match);$where_clause.=' ORDER BY "'.str_replace('.','"."',$order_match[1]).'"'.(isset($order_match[3])?' '.$order_match[3]:'');}}if(isset($where['LIMIT'])){$LIMIT=$where['LIMIT'];if(is_numeric($LIMIT)){$where_clause.=' LIMIT '.$LIMIT;}if(is_array($LIMIT)&&is_numeric($LIMIT[0])&&is_numeric($LIMIT[1])){if($this->database_type==='pgsql'){$where_clause.=' OFFSET '.$LIMIT[0].' LIMIT '.$LIMIT[1];}else {$where_clause.=' LIMIT '.$LIMIT[0].','.$LIMIT[1];}}}}else {if($where!=null){$where_clause.=' '.$where;}}return $where_clause;} protected function select_context($table,$join,&$columns=null,$where=null,$column_fn=null){$table='"'.$table.'"';$join_key=is_array($join)?array_keys($join):null;if(isset($join_key[0])&&strpos($join_key[0],'[')===0){$table_join=array();$join_array=array('>'=>'LEFT','<'=>'RIGHT','<>'=>'FULL','><'=>'INNER');foreach($join as $sub_table=>$relation){preg_match('/(\[(\<|\>|\>\<|\<\>)\])?([a-zA-Z0-9_\-]*)\s?(\(([a-zA-Z0-9_\-]*)\))?/',$sub_table,$match);if($match[2]!=''&&$match[3]!=''){if(is_string($relation)){$relation='USING ("'.$relation.'")';}if(is_array($relation)){if(isset($relation[0])){$relation='USING ("'.implode($relation,'", "').'")';}else {$joins=array();foreach($relation as $key=>$value){$joins[]=(strpos($key,'.')>0?'"'.str_replace('.','"."',$key).'"':$table.'."'.$key.'"').' = '.'"'.(isset($match[5])?$match[5]:$match[3]).'"."'.$value.'"';}$relation='ON '.implode($joins,' AND ');}}$table_join[]=$join_array[$match[2]].' JOIN "'.$match[3].'" '.(isset($match[5])?'AS "'.$match[5].'" ':'').$relation;}}$table.=' '.implode($table_join,' ');}else {if(is_null($columns)){if(is_null($where)){if(is_array($join)&&isset($column_fn)){$where=$join;$columns=null;}else {$where=null;$columns=$join;}}else {$where=$join;$columns=null;}}else {$where=$columns;$columns=$join;}}if(isset($column_fn)){if($column_fn==1){$column='1';if(is_null($where)){$where=$columns;}}else {if(empty($columns)){$columns='*';$where=$join;}$column=$column_fn.'('.$this->column_push($columns).')';}}else {$column=$this->column_push($columns);}return 'SELECT '.$column.' FROM '.$table.$this->where_clause($where);} public function select($table,$join,$columns=null,$where=null){$query=$this->query($this->select_context($table,$join,$columns,$where));return $query?$query->fetchAll((is_string($columns)&&$columns!='*')?PDO::FETCH_COLUMN:PDO::FETCH_ASSOC):false;} public function insert($table,$datas){$lastId=array();if(!isset($datas[0])){$datas=array($datas);}foreach($datas as $data){$values=array();$columns=array();foreach($data as $key=>$value){array_push($columns,$this->column_quote($key));switch(gettype($value)){case 'NULL':$values[]='NULL';break;case 'array':preg_match("/\(JSON\)\s*([\w]+)/i",$key,$column_match);$values[]=isset($column_match[0])?$this->quote(json_encode($value)):$this->quote(serialize($value));break;case 'boolean':$values[]=($value?'1':'0');break;case 'integer':case 'double':case 'string':$values[]=$this->fn_quote($key,$value);break;}}$this->exec('INSERT INTO "'.$table.'" ('.implode(', ',$columns).') VALUES ('.implode($values,', ').')');$lastId[]=$this->pdo->lastInsertId();}return count($lastId)>1?$lastId:$lastId[0];} public function update($table,$data,$where=null){$fields=array();foreach($data as $key=>$value){preg_match('/([\w]+)(\[(\+|\-|\*|\/)\])?/i',$key,$match);if(isset($match[3])){if(is_numeric($value)){$fields[]=$this->column_quote($match[1]).' = '.$this->column_quote($match[1]).' '.$match[3].' '.$value;}}else {$column=$this->column_quote($key);switch(gettype($value)){case 'NULL':$fields[]=$column.' = NULL';break;case 'array':preg_match("/\(JSON\)\s*([\w]+)/i",$key,$column_match);$fields[]=$column.' = '.$this->quote(isset($column_match[0])?json_encode($value):serialize($value));break;case 'boolean':$fields[]=$column.' = '.($value?'1':'0');break;case 'integer':case 'double':case 'string':$fields[]=$column.' = '.$this->fn_quote($key,$value);break;}}}return $this->exec('UPDATE "'.$table.'" SET '.implode(', ',$fields).$this->where_clause($where));} public function delete($table,$where){return $this->exec('DELETE FROM "'.$table.'"'.$this->where_clause($where));} public function replace($table,$columns,$search=null,$replace=null,$where=null){if(is_array($columns)){$replace_query=array();foreach($columns as $column=>$replacements){foreach($replacements as $replace_search=>$replace_replacement){$replace_query[]=$column.' = REPLACE('.$this->column_quote($column).', '.$this->quote($replace_search).', '.$this->quote($replace_replacement).')';}}$replace_query=implode(', ',$replace_query);$where=$search;}else {if(is_array($search)){$replace_query=array();foreach($search as $replace_search=>$replace_replacement){$replace_query[]=$columns.' = REPLACE('.$this->column_quote($columns).', '.$this->quote($replace_search).', '.$this->quote($replace_replacement).')';}$replace_query=implode(', ',$replace_query);$where=$replace;}else {$replace_query=$columns.' = REPLACE('.$this->column_quote($columns).', '.$this->quote($search).', '.$this->quote($replace).')';}}return $this->exec('UPDATE "'.$table.'" SET '.$replace_query.$this->where_clause($where));} public function get($table,$join=null,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where).' LIMIT 1');if($query){$data=$query->fetchAll(PDO::FETCH_ASSOC);if(isset($data[0])){$column=$where==null?$join:$column;if(is_string($column)&&$column!='*'){return $data[0][$column];}return $data[0];}else {return false;}}else {return false;}} public function has($table,$join,$where=null){$column=null;$query=$this->query('SELECT EXISTS('.$this->select_context($table,$join,$column,$where,1).')');return $query?$query->fetchColumn()==='1':false;} public function count($table,$join=null,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where,'COUNT'));return $query?0+$query->fetchColumn():false;} public function max($table,$join,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where,'MAX'));if($query){$max=$query->fetchColumn();return is_numeric($max)?$max+0:$max;}else {return false;}} public function min($table,$join,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where,'MIN'));if($query){$min=$query->fetchColumn();return is_numeric($min)?$min+0:$min;}else {return false;}} public function avg($table,$join,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where,'AVG'));return $query?0+$query->fetchColumn():false;} public function sum($table,$join,$column=null,$where=null){$query=$this->query($this->select_context($table,$join,$column,$where,'SUM'));return $query?0+$query->fetchColumn():false;} public function debug(){$this->debug_mode=true;return $this;} public function error(){return $this->pdo->errorInfo();} public function last_query(){return end($this->logs);} public function log(){return $this->logs;} public function info(){$output=array('server'=>'SERVER_INFO','driver'=>'DRIVER_NAME','client'=>'CLIENT_VERSION','version'=>'SERVER_VERSION','connection'=>'CONNECTION_STATUS');foreach($output as $key=>$value){$output[$key]=$this->pdo->getAttribute(constant('PDO::ATTR_'.$value));}return $output;} 15 | } 16 | ?> --------------------------------------------------------------------------------