mirror of
				https://github.com/pierre42100/ComunicAPI
				synced 2025-11-03 19:54:14 +00:00 
			
		
		
		
	Setup API requests limit system.
This commit is contained in:
		
							
								
								
									
										135
									
								
								classes/APILimits.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								classes/APILimits.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * API Actions limits count
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Pierre HUBERT
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class APILimits {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Table name
 | 
			
		||||
	 */
 | 
			
		||||
	const TABLE_NAME = DBprefix."api_limit_count";
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Entries live time
 | 
			
		||||
	 */
 | 
			
		||||
	const KEEP_DATA_FOR = 3600; // 1 hour
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Actions list
 | 
			
		||||
	 */
 | 
			
		||||
	const ACTION_LOGIN_FAILED = "failed_login";
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Actions configruation
 | 
			
		||||
	 */
 | 
			
		||||
	const ACTIONS = array(
 | 
			
		||||
 | 
			
		||||
		//Login failed
 | 
			
		||||
		self::ACTION_LOGIN_FAILED => array(
 | 
			
		||||
			"limit" => 10
 | 
			
		||||
		)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Limit the number of time a client can perform a query over the API
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string $action The name of the action to limit
 | 
			
		||||
	 * @param bool $trigger Specify whether this call of the method must be
 | 
			
		||||
	 * considered as a call of the client or not
 | 
			
		||||
	 */
 | 
			
		||||
	public function limit_query(string $action, bool $trigger){
 | 
			
		||||
 | 
			
		||||
		//First, clean old entries
 | 
			
		||||
		$this->clean();
 | 
			
		||||
 | 
			
		||||
		$ip = $_SERVER["REMOTE_ADDR"];
 | 
			
		||||
 | 
			
		||||
		//If required, increase action by one
 | 
			
		||||
		if($trigger)
 | 
			
		||||
			$this->trigger($action, $ip);
 | 
			
		||||
		
 | 
			
		||||
		//Count the number of time the action occurred
 | 
			
		||||
		if($this->count($action, $ip) > self::ACTIONS[$action]["limit"])
 | 
			
		||||
			Rest_fatal_error(429, "Too many request. Please try again later.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clean old entries
 | 
			
		||||
	 */
 | 
			
		||||
	public function clean(){
 | 
			
		||||
		db()->deleteEntry(
 | 
			
		||||
			self::TABLE_NAME,
 | 
			
		||||
			"time_start < ?",
 | 
			
		||||
			array(time() - self::KEEP_DATA_FOR)
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Increase by one the number of the time a client performed
 | 
			
		||||
	 * an action
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string $action The action to trigger
 | 
			
		||||
	 * @param string $ip The target IP address
 | 
			
		||||
	 * @return bool TRUE for a success else FALSE
 | 
			
		||||
	 */
 | 
			
		||||
	private function trigger(string $action, string $ip) : bool {
 | 
			
		||||
 | 
			
		||||
		if(!$this->exists($action, $ip)){
 | 
			
		||||
			return db()->addLine(self::TABLE_NAME, array(
 | 
			
		||||
				"ip" => $ip,
 | 
			
		||||
				"time_start" => time(),
 | 
			
		||||
				"action" => $action,
 | 
			
		||||
				"count" => 1
 | 
			
		||||
			));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			
 | 
			
		||||
			$number = $this->count($action, $ip);
 | 
			
		||||
			$number++;
 | 
			
		||||
 | 
			
		||||
			return db()->updateDB(self::TABLE_NAME,
 | 
			
		||||
				"ip = ? AND action = ?",
 | 
			
		||||
				array("count" => $number),
 | 
			
		||||
				array($ip, $action));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Check wether an action has been referenced at least once in
 | 
			
		||||
	 * the database
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string $action The action to check
 | 
			
		||||
	 * @param string $ip The target IP address
 | 
			
		||||
	 * @return bool TRUE if the entry has been found at least once / FALSE else
 | 
			
		||||
	 */
 | 
			
		||||
	private function exists(string $action, string $ip) : bool {
 | 
			
		||||
		return db()->count(self::TABLE_NAME, 
 | 
			
		||||
			"WHERE ip = ? AND action = ?",
 | 
			
		||||
			array($ip, $action)) > 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Count the number of time an IP address has performed an action
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string $action The target action
 | 
			
		||||
	 * @param string $ip Target IP address
 | 
			
		||||
	 * @return int The number of time the action has been done
 | 
			
		||||
	 */
 | 
			
		||||
	private function count(string $action, string $ip) : int {
 | 
			
		||||
		$data = db()->select(self::TABLE_NAME, 
 | 
			
		||||
			"WHERE ip = ? AND action = ?",
 | 
			
		||||
			array($ip, $action),
 | 
			
		||||
			array("count"));
 | 
			
		||||
		
 | 
			
		||||
		if(count($data) < 1)
 | 
			
		||||
			return 1;
 | 
			
		||||
		
 | 
			
		||||
		else
 | 
			
		||||
			return $data[0]["count"];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user