2023-05-16 10:50:42 +08:00

909 lines
30 KiB
PHP

<?php
/**
* Model file of im module.
*
* @copyright Copyright 2009-2020 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @author Xiying Guan <guanxiying@cnezsoft.com>
* @package im
* @license ZOSL (http://zpl.pub/page/zoslv1.html)
* @version $Id$
* @Link http://xuan.im
*/
class imModel extends model
{
/**
* Sub-model list, these models are stored at im/model/.
*
* @access public
*/
public $models = array('chat', 'message', 'user', 'conference', 'bot');
/**
* __construct loads and inits sub-models.
*
* @access public
* @return void
*/
public function __construct()
{
parent::__construct();
if((isset($_SERVER['RR_RELAY']) || isset($_SERVER['RR_MODE'])) && !commonModel::isLicensedMethod('im', 'roadrunner')) die;
$modelPath = dirname(__FILE__) . DS . "model" . DS;
foreach($this->models as $model)
{
helper::import($modelPath . "$model.php");
$className = "im$model";
$this->$model = new $className($this->appName, $this);
}
}
/**
* Get apiScheme info.
*
* @param string $key
* @access public
* @return mixed
*/
public function getApiScheme($key = '')
{
$schemeFile = $this->app->getExtensionRoot() . 'xuan/im/apischeme.json';
$scheme = json_decode(trim(file_get_contents($schemeFile)), true);
if(!$key) return $scheme;
return zget($scheme, $key, '');
}
/**
* Send formatted output.
*
* @param array|object $output Example: array('result' => 'success', 'data' => $messages, 'users' => $userIdList, ...);
* @param string $schemeName
* @access public
* @return void
*/
public function sendOutput($output, $schemeName = 'RAW')
{
$output = $this->formatOutput($output, $schemeName);
return $this->app->output($this->app->encrypt($output));
}
/**
* Send formatted output group.
*
* @param array|object $outputs Example: array('result' => 'success', 'data' => $messages, 'users' => $userIdList, ...);
* @access public
* @return void
*/
public function sendOutputGroup($outputs)
{
$formatted = array();
foreach($outputs as $output)
{
if(!isset($firstOutput)) $firstOutput = $output;
if(!isset($output->method))
{
$stack = debug_backtrace(false, 2);
$output->method = isset($stack[1]) ? $stack[1]['function'] : '';
}
$formatted[] = $this->formatOutput($output, strtolower($output->method) . 'Response', $returnRaw = true);
}
$userID = isset($firstOutput->userID) ? $firstOutput->userID : 0;
$method = isset($firstOutput->method) ? $firstOutput->method : '';
$result = isset($firstOutput->result) ? $firstOutput->result : 'success';
$finalOutput = $this->appendResponseHeader($formatted, $userID, $firstOutput->users, $method, $result);
return $this->app->output($this->app->encrypt($finalOutput));
}
/**
* Format output data.
*
* @param array|object $data Example: array('result' => 'success', 'data' => $messages, 'users' => $userIdList, ...);
* @param string $map
* @param bool $returnRaw
* @param bool $prependName
* @access public
* @return object|string
*/
public function formatOutput($data, $map = 'RAW', $returnRaw = false, $prependName = true)
{
if(!empty($this->app->debug)) $this->app->log("format output($map): " . json_encode($data));
$output = new stdclass();
foreach($data as $key => $value)
{
if($key == 'users' && !is_array($value)) $value = array((int) $value);
$output->$key = $value;
}
$output->device = zget($this->app->input, 'device', 'desktop');
$output->userID = zget($data, 'userID', '0');
$output->result = zget($data, 'result', 'success');
$output->method = zget($data, 'method', $this->app->getMethodName());
$output->rid = zget($this->app->input, 'rid');
if($map != 'RAW')
{
$maps = zget($this->config->maps, $map, array());
/* Using requestPack as fallback maps */
if(empty($maps)) $maps = zget($this->config->maps, 'responsePack');
$data = self::encodeOutput($output, $maps);
}
else
{
$map = strtolower($output->method) . 'Response';
}
$data = $prependName ? array($map, $data) : $data;
if(!empty($this->app->debug)) $this->app->log("encoded output($map): " . json_encode($data));
if($returnRaw) return $data;
$users = isset($output->users) ? $output->users : array();
return $this->appendResponseHeader($data, $output->userID, $users, $output->method, $output->result);
}
/**
* Encode output.
*
* @param object $output
* @param object|string|boolean $map
* @static
* @access public
* @return array|object
*/
public static function encodeOutput($output, $map)
{
if(empty($map)) return $output;
$output = (array) $output;
/* If map is not final map array, decode with map's dataType setting.*/
if(isset($map['name']) and isset($map['dataType'])) $map = $map['dataType'];
if(isset($map['name']) and !isset($map['dataType'])) $map = array($map);
$data = array();
foreach($map as $key => $prop)
{
$indexName = $prop['name'];
if($prop['type'] == 'basic')
{
if(isset($prop['options']))
{
$options = array_flip($prop['options']);
$data[$key] = zget($options, zget($output, $indexName, ''));
}
else
{
$data[$key] = zget($output, $indexName, '');
}
continue;
}
if($prop['type'] == 'object')
{
if(isset($output[$indexName])) $data[$key] = self::encodeOutput($output[$indexName], $prop['dataType']);
continue;
}
if($prop['type'] == 'list')
{
$tmpOutput = array();
if(isset($output[$indexName]))
{
foreach($output[$indexName] as $item)
{
$tmpOutput[] = self::encodeOutput($item, $prop['dataType']);
}
}
$data[$key] = $tmpOutput;
}
}
return $data;
}
/**
* Batch encode output.
*
* @param array $array
* @param bool|object|string $map
* @static
* @access public
* @return array
*/
public static function batchEncodeOutput($array, $map)
{
$data = array();
if(empty($array)) return $data;
foreach($array as $output) $data[] = self::encodeOutput($output, $map);
return $data;
}
/**
* Append header for xxd to response.
*
* @param array $output
* @param string $from current user id
* @param string|int|array $to id list of users to notify : 123,2,3,4,76,423
* @param string $method
* @param string $result
* @access public
* @return string
*/
public function appendResponseHeader($output, $from, $to = 0, $method = '', $result = 'success')
{
if(empty($to)) $to = $this->app->input['userID'];
elseif(is_array($to)) $to = implode(',', $to);
if(!$method) $method = strtolower($this->app->getMethodName());
$device = $this->app->input['device'];
$lang = $this->app->input['lang'];
if(!isset($from) || empty($from)) $from = $this->app->input['userID'];
$response = "{$to}\n";
$response .= "{$from}\n";
$response .= "$method\n";
$response .= "success\n";
$response .= "{$device}\n";
$response .= "{$lang}\n";
if(is_array($output) && !is_string($output[0]))
{
foreach($output as $op) $response .= json_encode($op) . "\n";
$response = trim($response);
}
else
{
$response .= json_encode($output);
}
return $response;
}
/**
* Get output data of user list.
*
* @param array $identities
* @param int $userID
* @param bool $returnRaw
* @access public
* @return object
*/
public function getUserListOutput($identities, $userID, $returnRaw = false)
{
$output = new stdclass();
$users = $this->userGetList($status = '', $identities, $idAsKey = false);
if(dao::isError())
{
$output->result = 'fail';
$output->message = 'Get userlist failed.';
return $this->formatOutput($output, 'messageResponsePack', $returnRaw);
}
else
{
$output->result = 'success';
$output->users = $userID;
$output->data = $users;
$output->method = 'usergetlist';
if(empty($identities))
{
$this->app->loadLang('user');
$roles = $this->lang->user->roleList;
$allDepts = $this->loadModel('dept')->getListByType('dept');
$depts = array();
foreach($allDepts as $id => $dept)
{
$depts[$id] = array('name' => $dept->name, 'order' => (int)$dept->order, 'parent' => (int)$dept->parent);
}
$output->roles = $roles;
$output->depts = $depts;
}
else
{
$output->partial = $identities;
}
}
return $this->formatOutput($output, 'usergetlistResponse', $returnRaw);
}
/**
* Get output data of chat list.
*
* @param int $userID
* @param bool $returnRaw
* @param string $chatList
* @access public
* @return object
*/
public function getChatListOutput($userID, $returnRaw = false, $chatList = '')
{
if(empty($chatList)) $chatList = $this->chatGetListByUserID($userID);
if(dao::isError()) return $this->formatOutput(array('result' => 'fail', 'message' => 'Get chat list fail.'), 'messageResponsePack', $returnRaw);
return $this->formatOutput(array('result' => 'success', 'method' => 'chatgetlist', 'data' => $chatList, 'users' => $userID), 'chatgetlistResponse', $returnRaw);
}
/**
* Get output data of offline messages.
*
* @param int $userID
* @param bool $returnRaw
* @access public
* @return object
*/
public function getOfflineMessagesOutput($userID, $returnRaw = false)
{
$messages = $this->messageGetOfflineList($userID);
if(empty($messages)) return $this->formatOutput(array('result' => 'fail', 'message' => 'Get offline messages list fail.'), 'messageResponsePack', $returnRaw);
if(dao::isError()) return $this->formatOutput(array('result' => 'fail', 'message' => 'Get offline messages list fail.'), 'messageResponsePack', $returnRaw);
return $this->formatOutput(array('result' => 'success', 'method' => 'messagesend', 'data' => $messages, 'users' => $userID), 'messagesendResponse', $returnRaw);
}
/**
* Get output data of offline notify.
*
* @param int $userID
* @param bool $returnRaw
* @access public
* @return object
*/
public function getOfflineNotifyOutput($userID, $returnRaw = false)
{
$messages = $this->messageGetNotifyByUserID($userID);
if(empty($messages)) return null;
if(dao::isError()) return $this->formatOutput(array('result' => 'fail', 'message' => 'Get offline notification list fail.'), 'messageResponsePack', $returnRaw);
return $this->formatOutput(array('result' => 'success', 'method' => 'syncnotifications', 'data' => $messages, 'users' => $userID), 'syncnotificationsResponse', $returnRaw);
}
/**
* Get output data of open conferences.
*
* @param int $userID
* @param boolean $returnRaw
* @param string $userChatList
* @access public
* @return object
*/
public function getOpenConferencesOutput($userID, $returnRaw = false, $userChatList = '', $ignoreActions = false)
{
if(empty($userChatList)) $userChatList = $this->chatGetListByUserID($userID);
$conferences = $this->conferenceGetOpenConferencesByChatList($userChatList, $userID, $ignoreActions);
if(empty($conferences)) return null;
if(dao::isError()) return $this->formatOutput(array('result' => 'fail', 'message' => 'Get open conferences list fail.'), 'messageResponsePack', $returnRaw);
return $this->formatOutput(array('result' => 'success', 'method' => 'syncconferences', 'data' => $conferences, 'users' => $userID), 'syncconferencesResponse', $returnRaw);
}
/**
* Create gid.
* @access public
* @return string
*/
public static function createGID()
{
$id = md5(microtime() . mt_rand());
return substr($id, 0, 8) . '-' . substr($id, 8, 4) . '-' . substr($id, 12, 4) . '-' . substr($id, 16, 4) . '-' . substr($id, 20, 12);
}
/**
* Download xxd.
*
* @param object $setting
* @param string $downloadType
* @access public
* @return array
*/
public function downloadXXD($setting, $downloadType)
{
set_time_limit(0);
$system = $this->getSystem($setting->os);
$version = $this->config->xuanxuan->version;
$xxdDirectory = $this->app->tmpRoot . 'xxd' . DS . $version;
$basePackage = $xxdDirectory . DS . $system . ".base.zip";
$xxdFileName = 'xxd.' . $version . ".$system" . ".zip";
$downloadCDNLink = $this->config->im->xxdDownloadUrl . $version . "/xxd." . $version . ".$system" . ".zip";
if(!is_dir($xxdDirectory)) mkdir($xxdDirectory, 0777, true);
if(!file_exists($basePackage) && $downloadType == 'package')
{
$agent = $this->app->loadClass('snoopy');
$agent->fetch($downloadCDNLink);
$error = json_decode($agent->results)->error;
if(!empty($error)) return array('result' => 'fail', 'message' => "$basePackage is not exists");
$fopenPackage = fopen($basePackage, "w");
fwrite($fopenPackage, $agent->results);
}
$data = new stdClass();
$data->xxdDirectory = $xxdDirectory;
$data->sslcrt = $setting->sslcrt;
$data->sslkey = $setting->sslkey;
$data->basePackage = $basePackage;
$data->xxdFileName = $xxdFileName;
$data->host = trim($this->getServer(), '/') . (zget($this->config->xuanxuan, 'backend', 'xxb') == 'ranzhi' ? dirname($this->config->webRoot) : $this->config->webRoot);
$data->ip = $setting->ip ?: '0.0.0.0';
$data->commonPort = $setting->commonPort ?: '11443';
$data->chatPort = $setting->chatPort ?: '11444';
$data->https = $setting->https ?: 'on';
$data->enableAES = $setting->aes == 'off' ? 0 : 1;
$data->uploadPath = 'files/';
$data->uploadFileSize = $setting->uploadFileSize ?: '20';
$data->pollingInterval = isset($this->config->xuanxuan->pollingInterval) ? $this->config->xuanxuan->pollingInterval : 15;
$data->maxOnlineUser = isset($setting->maxOnlineUser) ? $setting->maxOnlineUser : 0;
$data->logPath = 'log/';
$data->certPath = 'cert/';
$data->debug = 0;
$data->key = $this->config->xuanxuan->key;
$data->syncConfig = 1;
$data->thumbnail = 1;
if($downloadType == 'config')
{
$configContent = $this->createXxdConfigFile($data);
if(!empty($configContent)) $this->loadModel('file')->sendDownHeader('xxd.conf', 'conf', $configContent['zh']);
}
elseif($downloadType == 'package')
{
$packageFileName = $this->createXxdPackage($data);
if(!empty($packageFileName)) return array('result' => 'success', 'message' => helper::createLink('im', 'downloadXxdPackage', "xxdFileName=$xxdFileName"));
}
return array('result' => 'fail', 'message' => 'error');
}
/**
* create xxd config file
*
* @param object $setting
* @access public
* @return array
*/
public function createXxdConfigFile($setting)
{
$configParamsList = $this->config->im->xxdConfig;
// Replace template variable.
$lineMaxLength = 0;
foreach($configParamsList as $configParams)
{
if($configParams == 'host' || $configParams == 'key')
{
$config[$configParams] = $setting->$configParams;
}
elseif(strpos($configParams, '=') !== false)
{
$configItem = explode('=', $configParams);
$config[$configItem[0]] = $configItem[0] . '=' . $configItem[1];
}
else
{
$config[$configParams] = $configParams . '=' . $setting->$configParams;
if($configParams == 'uploadFileSize') $config[$configParams] .= 'M';
}
$lineMaxLength = strlen($configParams) > $lineMaxLength ? strlen($configParams) : $lineMaxLength;
}
$lineMaxLength += 10;
// Add parameter notes
$contentZH = '[server]' . "\n";
$contentEN = '[server]' . "\n";
foreach($config as $type => $configValue)
{
if($type == 'host' || $type == 'key') continue;
$configValue = str_replace(PHP_EOL, '', $configValue);
$configlength = strlen($configValue);
for($i = 0; $i < ($lineMaxLength - $configlength); $i++) $configValue .= ' ';
$contentZH .= $configValue . $this->lang->im->xxdConfigNote['zh'][$type] . "\n";
$contentEN .= $configValue . $this->lang->im->xxdConfigNote['en'][$type] . "\n";
}
// Add backend
$backend = "\n" . '[backend]' . "\n";
$backendFoot = 'default=' . $config['host'] . 'x.php,' . $config['key'];
$backendFoot = str_replace(PHP_EOL, '', $backendFoot) . "\n";
$backendZH = $backend . $this->lang->im->xxdConfigNote['zh']['backend'] . "\n" . $backendFoot;
$backendEN = $backend . $this->lang->im->xxdConfigNote['en']['backend'] . "\n" . $backendFoot;
$contentZH .= $backendZH;
$contentEN .= $backendEN;
return array('zh' => $contentZH, 'en' => $contentEN);
}
/**
* create xxd package
*
* @param object
* @access public
* @return string
*/
public function createXxdPackage($setting)
{
$configContent = $this->createXxdConfigFile($setting);
if(empty($configContent)) return false;
// unzip package
$this->app->loadClass('pclzip', true);
$basePackage = new pclzip($setting->basePackage);
$result = $basePackage->extract(
PCLZIP_OPT_PATH, $setting->xxdDirectory
);
if($result == 0) $basePackage->errorInfo(true);
// Replace config file.
$baseFilePath = $result[0]['filename'];
$packageName = $result[0]['stored_filename'];
unlink($baseFilePath . 'config/xxd.conf');
unlink($baseFilePath . 'config/xxd.en.conf');
file_put_contents($baseFilePath . 'config/xxd.conf', $configContent['zh']);
file_put_contents($baseFilePath . 'config/xxd.en.conf', $configContent['en']);
// https add certificate
if(isset($setting->https) && $setting->https == 'on')
{
if(!is_dir($baseFilePath . 'cert')) mkdir($baseFilePath . 'cert', 0777);
file_put_contents($baseFilePath . 'cert/xxd.crt', $setting->sslcrt);
file_put_contents($baseFilePath . 'cert/xxd.key', $setting->sslkey);
}
// zip xxd file
chdir($setting->xxdDirectory);
$xxdZipName = $setting->xxdDirectory . "/" . $setting->xxdFileName;
$xxdZip = new pclzip($xxdZipName);
$xxdResult = $xxdZip->create($packageName, PCLZIP_OPT_TEMP_FILE_ON);
if($xxdResult == 0) return false;
return $xxdResult[0]['filename'];
}
/**
* revise operating system name.
*
* @param string $os name
* @access public
* @return string
*/
public function getSystem($os)
{
return zget($this->config->im->osMap, $os, 'win64');
}
/**
* Get server.
*
* @access public
* @return string
*/
public function getServer()
{
if(!empty($this->config->xuanxuan->server)) return $this->config->xuanxuan->server;
return commonModel::getSysURL();
}
/**
* UploadFile a file.
*
* @param string $fileName
* @param string $path
* @param int $size
* @param int $time
* @param int $userID
* @param string $users
* @param object $chat
* @access public
* @return int
*/
public function uploadFile($fileName, $path, $size, $time, $userID, $users, $chat)
{
$user = $this->userGetByID($userID);
$extension = $this->loadModel('file')->getExtension($fileName); // if file has no extension or is "danger",return "txt, but $fileName is the origin file name"
$file = new stdclass();
$file->pathname = $path;
$file->title = preg_replace("/\.$extension$/", '', $fileName);
$file->extension = $extension;
$file->size = $size;
$file->objectType = 'chat';
$file->objectID = $chat->id;
$file->createdBy = !empty($user->account) ? $user->account : '';
$file->createdDate = date(DT_DATETIME1, $time);
$this->dao->insert(TABLE_FILE)->data($file)->exec();
$fileID = $this->dao->lastInsertID();
$path .= md5($fileName . $fileID . $time);
$this->dao->update(TABLE_FILE)->set('pathname')->eq($path)->where('id')->eq($fileID)->exec();
return $fileID;
}
/**
* Save xxd start time.
*
* @access public
* @return bool
*/
public function setXxdStartTime()
{
$this->loadModel('setting')->setItem('system.common.xxd.start', helper::now());
return !dao::isError();
}
/**
* update last poll.
*
* @access public
* @return void
*/
public function updateLastPoll()
{
$this->loadModel('setting')->setItem('system.common.xxd.lastPoll', helper::now());
}
/**
* check xxb config.
*
* @access public
* @return bool
*/
public function checkXXBConfig()
{
$xxbConfig = $this->config->xuanxuan;
$notEmptyFields = array('key', 'server', 'ip', 'chatPort', 'commonPort');
foreach($notEmptyFields as $field) if(empty($xxbConfig->$field)) return false;
if($xxbConfig->https == 'on' && (empty($xxbConfig->sslcrt) || empty($xxbConfig->sslkey))) return false;
return true;
}
/**
* Get xxd run time.
*
* @param int $timestamp
* @param int $count
* @access public
* @return string
*/
public function getXxdRunTime($timestamp, $count = 0)
{
if($count > 1) return '';
if($timestamp > 86400)
{
return floor($timestamp / 86400) . $this->lang->im->day . $this->getXxdRunTime($timestamp%86400, ++$count);
}
else if($timestamp > 3600)
{
return floor($timestamp / 3600) . $this->lang->im->hours . $this->getXxdRunTime($timestamp%3600, ++$count);
}
else if($timestamp > 60)
{
return floor($timestamp / 60) . $this->lang->im->minute . $this->getXxdRunTime($timestamp%60, ++$count);
}
else
{
return $timestamp . $this->lang->im->secs;
}
}
/**
* Get xxd status.
*
* @access public
* @return string
*/
public function getXxdStatus()
{
$this->app->loadLang('client');
$now = helper::now();
$xxdStatus = 'offline';
$polling = empty($this->config->xuanxuan->pollingInterval) ? 60 : $this->config->xuanxuan->pollingInterval;
$lastPoll = $this->loadModel('setting')->getItem("owner=system&module=common&section=xxd&key=lastPoll");
$xxdStartDate = zget($this->config->xxd, 'start', $this->lang->client->noData);
if((strtotime($now) - strtotime($xxdStartDate) < $polling) || (strtotime($now) - strtotime($lastPoll)) < (3 + $polling))
{
$xxdStatus = 'online';
}
else if((strtotime($now) - strtotime($lastPoll)) > (3 + $polling))
{
$xxdStatus = 'offline';
}
return $xxdStatus;
}
/**
* Get signed time.
* Other program can extend this function.
*
* @param string $account
* @access public
* @return string | int
*/
public function getSignedTime($account = '')
{
return 0;
}
/**
* Get extension list.
* @param $userID
* @return array
*/
public function getExtensionList($userID)
{
$entries = array();
$allEntries = array();
$time = time();
$baseURL = commonModel::getSysURL();
$entryList = $this->dao->select('*')->from(TABLE_ENTRY)->orderBy('`order`, id')->fetchAll();
$files = $this->dao->select('id, pathname, objectID')->from(TABLE_FILE)->where('objectType')->eq('entry')->fetchAll('objectID');
foreach($entryList as $entry)
{
$data = new stdclass();
$data->id = $entry->id;
$data->url = strpos($entry->login, 'http') !== 0 ? str_replace('../', $baseURL . $this->config->webRoot, $entry->login) : $entry->login;
$allEntries[] = $data;
}
$_SERVER['SCRIPT_NAME'] = str_replace('x.php', 'index.php', $_SERVER['SCRIPT_NAME']);
foreach($entryList as $entry)
{
if($entry->status != 'online') continue;
if(strpos(',' . $entry->platform . ',', ',xuanxuan,') === false) continue;
$token = '';
if(isset($files[$entry->id]->pathname))
{
$token = '&time=' . $time . '&token=' . md5($files[$entry->id]->pathname . $time);
}
$data = new stdClass();
$data->entryID = (int)$entry->id;
$data->name = $entry->code;
$data->displayName = $entry->name;
$data->abbrName = $entry->abbr;
$data->optional = $entry->optional;
$data->enable = $entry->enable;
$data->webViewUrl = strpos($entry->login, 'http') !== 0 ? str_replace('../', $baseURL . $this->config->webRoot, $entry->login) : $entry->login;
$data->download = empty($entry->package) ? '' : $baseURL . helper::createLink('file', 'download', "fileID={$entry->package}&mouse=" . $token);
$data->md5 = empty($entry->package) ? '' : md5($entry->package);
$data->logo = empty($entry->logo) ? '' : $baseURL . $this->config->webRoot . ltrim($entry->logo, '/');
if($entry->sso) $data->data = $allEntries;
$entries[] = $data;
}
return $entries;
}
/**
* transfer ip to number
*
* @param string $ip
* @return int
*/
public function getIPLong($ip) {
return bindec(decbin(ip2long($ip)));
}
/**
* Check whether IP is valid
*
* @param string $ip
* @return bool
*/
public function checkIPValidity($ip) {
if(filter_var($ip, FILTER_VALIDATE_IP)) return true;
return false;
}
/**
* Check whether CIDR is valid
*
* @param string $ip
* @return bool
*/
public function checkCIDRValidity($cidr)
{
$parts = explode('/', $cidr);
if(count($parts) != 2) return false;
$ip = $parts[0];
if(!$this->checkIPValidity($ip)) return false;
$netmask = $parts[1];
if(!is_numeric($netmask)) return false;
$netmask = intval($parts[1]);
if($netmask < 0 || $netmask > 32) return false;
return true;
}
/**
* check whether IP in CIDR
* @param string|number $ip
* @param string $cidr
* @return bool
*/
public function checkIPInCIDR($ip, $cidr)
{
$cidr = explode('/', $cidr);
if(is_string($ip)) $ip = $this->getIPLong($ip);
$startIp = long2ip((ip2long($cidr[0])) & ((-1 << (32 - (int)$cidr[1]))));
$endIp = long2ip((ip2long($startIp)) + pow(2, (32 - (int)$cidr[1])) - 1);
$startIp = $this->getIPLong($startIp);
$endIp = $this->getIPLong($endIp);
return $ip >= $startIp && $ip <= $endIp;
}
/**
* check whether IP in CIDRs
* @param string $ip
* @param string $startIp
* @param string $endIp
* @return bool
*/
public function checkIPInCIDRs($ip, $cidrs)
{
$originCidrs = $cidrs;
$cidrs = explode(',', $cidrs);
if(count($cidrs) == 0)
{
if($this->checkCIDRValidity($originCidrs))
{
$cidrs = array($originCidrs);
}
else
{
return false;
}
}
$ip = $this->getIPLong($ip);
foreach($cidrs as $cidr) if($this->checkIPInCIDR($ip, $cidr)) return true;
return false;
}
/**
* __call functions defined in model.
*
* @param string $function
* @param array $arguments
* @access public
* @return void
*/
public function __call($function, $arguments)
{
foreach($this->models as $model)
{
if(strpos(strtolower($function), $model) === 0)
{
$trimedFunction = substr($function, strlen($model));
if(is_callable(array($this->$model, $trimedFunction))) return call_user_func_array(array($this->$model, $trimedFunction), $arguments);
}
}
$this->app->triggerError("Method im::$function not exists.", __FILE__, __LINE__, $exit = true);
}
}