PHP (Статей: 62)

Для очередного клиента разрабатывал интернет-магазин запчастей. Каталога как такового там не было, однако была куча поставщиков, подключенных через API.
Так как клиентов планировалось много, то постоянное обращение к API было бы слишком затратно для сервера.
В рамках этого проекта был написан простой класс, который позволяет кэшировать данные, полученные в ходе каких-либо операций в файл и использовать их в любое удобное время с минимальной задержкой.
Вот он:
<?php
	/*
		Класс для кэширования данных
		Роман Сергеевич Гринько
		rsgrinko@gmail.com
		https://it-stories.ru
	*/
class CCache{
	private static $cache_dir;
	
	public static function init($dir){
		self::$cache_dir = $dir;
	}
	
	
	public static function checkCache($name){ // Проверка наличия элемента в кэше
		if(file_exists($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp')){
			return true;
		} else {
			return false;
		}
	}
	
	public static function getCache($name){	// Получить элемент из кэша
		if(self::checkCache($name)){
			return unserialize(base64_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp')));
		} else {
			return false;
		}
	}
		
	public static function writeCache($name, $arValue){ // Записать элемент в кэш
		if(file_put_contents($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp', base64_encode(serialize($arValue)))){
			return true;
		} else {
			return false;
		}
	}
	
	public static function clearCache(){ // Очистить кэш
		foreach(scandir($_SERVER['DOCUMENT_ROOT'].self::$cache_dir) as $file){
			if($file == '.' or $file == '..') continue;
			if(!unlink($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.$file)){
				return false;
			}
		}
		return true;
	}
	
	public static function delFromCache($name){ // Удалить элемент из кэша
		if(self::checkCache($name)){
			if(!unlink($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp')){
				return false;	
			}
		}
		return true;
	}	
	
	public static function getSize($name){ // Получить размер элемента в кэше
		if(self::checkCache($name)){
			return $_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp';
			
		}
		return true;
	}
	
	public static function getCacheSize(){ // Получить размер кэша
		$return_size = 0;
		foreach(scandir($_SERVER['DOCUMENT_ROOT'].self::$cache_dir) as $file){
			if($file == '.' or $file == '..') continue;
			$return_size = $return_size + filesize($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.$file);
		}
		return $return_size;
	}
	
	public static function ageOfCache($name) { // Получить возраст элемента кэша
		if(self::checkCache($name)){
			return  (time() - filectime($_SERVER['DOCUMENT_ROOT'].self::$cache_dir.md5($name).'.tmp'));
		} else {
			return false;
		}
	}
}
?>
Несмотря на малое количество строк кода, он с легкость решает поставленную задачу, а именно:
  • Проверка наличия кэша элемента
  • Получение элемента из кэша
  • Запись элемента в кэш
  • Удаление элемента из кэша
  • Очистку кэша
  • Получение размера кэша
  • Получение размера конкретного элемента в кэше
  • Время жизни элемента кэша

Все методы класса являются статическими, поэтому создавать экземпляр класса не требуется.
Ниже я приведу полное описание всех доступных методов.

CCache::init(‘/folder/’);
Установка дирректории для хранения кэша. Указывать со слешами в начале и в конце.

CCache::checkCache($name);
Выполняет проверку наличия кэша в базе. Принимает в качестве аргумента идентификатор элемента $name. Если элемент присутствует в кэше — вернет true, иначе — false.

CCache::getCache($name);
Получает элемент из кэша, возвращает массив. Если элемент в кэше не найден — вернет false.

CCache::writeCache($name, $arValue);
Запись данных в кэш. Принимает два аргумента: имя элемента $name и данные $arValue. В свою очередь данные $arValue должны являться массивом. При наличии элемента в кэше он будет перезаписан.

CCache::clearCache();
Метод полностью очищает кэш. Вернет false в случае ошибки.

CCache::delFromCache($name);
Метод удаляет конкретный элемент из кэша, принимает имя элемента $name в качестве аргумента. Вернет false в сллучае ошибки удаления.

CCache::getSize($name)
Метод возвращает размер элемента $name в байтах. Если элемент в кэше не найден — вернет false.

CCache::getSize($name)
Метод возвращает размер кэша в байтах

Небольшой пример использования:
<?php
require_once __DIR__.'/classes/CCache.php';

CCache::init('/cache/'); // устанавливаем дирректорию для кэша

// проверяем есть ли элемент в кэше и время его существования меньше часа
if(CCache::checkCache('test') and CCache::ageOfCache('test')<3600) {
  $var = CCache::getCache('test'); // получаем элемент из кэша
} else { // При отсутствии элемента в кэше 
  $var = $_SERVER; // Выполняем действия для получения этого элемента
  CCache::writeCache('test', $var); // Пишем результат в кэш
}

<?php

function _CURL_ ($url,$post) {
$ua = 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36';
$ch = curl_init($url);
curl_setopt_array($ch,array(
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_USERAGENT => $ua,
CURLOPT_COOKIEJAR => 'cookie.txt',
CURLOPT_COOKIEFILE => 'cookie.txt'
));
if (isset($post)) {
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
}
$html = curl_exec($ch);
curl_close($ch);
return $html;
}

if(!file_exists('cookie.txt')){
$log = file('log.txt');
$post = array(
'st.redirect' => '',
'st.posted' => 'set',
'st.email' => $log[0],
'st.password' => $log[1],
'st.screenSize' => '',
'st.browserSize' => '',
'st.flashVer' => ''
);
_CURL_ ('https://www.ok.ru/dk?cmd=AnonymLogin&st.cmd=AnonymLogin',http_build_query($post));
exit;
}

_CURL_ ('http://www.ok.ru');

?>
 

Это небольшой пример парсинга и авторизации с помощью cURL, все давольно легко и просто... Лично у меня данный скрипт лежит на хостинге и запускается с помощью CronTab каждую минуту, тоесть чисто показует постоянный онлайн на ok.ru ... Но до этого ради эксперемента шёл на большее.. Вплоть до того, что скрипт при запуске проверял на вхождение новых сообщений, читал их и при необходимости отвечал на них , и все работало без перебойно да и работает... Так же делал, что скрипт ходил по тем кто на сайте и кидал запросы на дружбу.. Затем просто надоели эти эксперименты и я все забросил , кода посеяли а заного писать влом... Но все в ваших руках, рабочий пример авторизации есть а дальше фантазируйте и пишите парсинг для автоматизации CronTab в помощь. По крайне мере функцию _CURL_ любому пригодится для парсинга.. Если надо чисто парсит странице то указуем только URL , если надо отправить POST запрос на сервер то указуем URL куда отправлять запрос и сами данные, например сообщение, логин, пароль... Ну вот и все
Доброе утро!

костыль
<?php
class MysqliEsc {
    protected $link = null;
    public function __construct($host, $user, $password, $database, $port = 3306, $socket = null) {
        $this->link = new \mysqli($host, $user, $password, $database, $port, $socket);
    }
    /**
     * 
     * @param string $sql sql запрос вида select * from таблица where поле = (%s, %i...)
     * @param array $params Массив!!! с параметрами (параметром)
     * @return \mysqli_result 
     */
    public function query($sql, array $params = []) {
        if ($params) {
            $sql = vsprintf($sql, array_filter($params, function ($param){
                return $this->link->real_escape_string($param);
            }));
        }
        return $this->link->query($sql);
    }
}
Использование
<?php
$db = new MysqliEsc('localhost', 'root', '', 'silex');
var_dump($db->query('select * from users where id = %i', [1])->fetch_array());
вернет

array (size=22)
0 => string '1' (length=1)
'id' => string '1' (length=1)
1 => string 'srv16rus@gmail.com' (length=18)
'email' => string 'srv16rus@gmail.com' (length=18)
2 => string 'HQZgK/c3tX6LXvqaPZowmQ+uyKtr4HjjMs9QMe6ZNYx6GHTa+hOV06N/tm7DSWqRFJLhiC+WySIVoZmnrzqGzg==' (length=88)
'password' => string 'HQZgK/c3tX6LXvqaPZowmQ+uyKtr4HjjMs9QMe6ZNYx6GHTa+hOV06N/tm7DSWqRFJLhiC+WySIVoZmnrzqGzg==' (length=88)
3 => string 'lapn8gh0q1ccww0so4g8k4oog80soc0' (length=31)
'salt' => string 'lapn8gh0q1ccww0so4g8k4oog80soc0' (length=31)
4 => string 'ROLE_USER' (length=9)
'roles' => string 'ROLE_USER' (length=9)
5 => string 'mmmmmmmmmmm' (length=11)
'name' => string 'mmmmmmmmmmm' (length=11)
6 => string '1419016035' (length=10)
'time_created' => string '1419016035' (length=10)
7 => null
'username' => null
8 => string '1' (length=1)
'isEnabled' => string '1' (length=1)
9 => null
'confirmationToken' => null
10 => null
'timePasswordResetRequested' => null

UPD Предложение от Башка:

<?php 
class MyMysqli extends mysqli{ 
  public function myQuery($query, $params){ 
    $stmt = $this->prepare($query); 
    $p = array_values($params); 
    array_unshift($p, array_keys($params)); 
    call_user_func_array([$stmt, 'bind_param'], $p); 
    $result = $stmt->execute(); 
    $stmt->close(); 
    return $result; 
  } 
}                                                              
$mysql = new MyMysqli("localhost", "my_user", "my_password", "world"); 
$mysql->myQuery('SELECT * FROM users WHERE login = ?', ['s' => 'admin']);
При написании скриптов у многих новичков и не только возникает проблема определения устройств
на офф сайте есть готовый класс, ниже показано как его использовать
<?php

//подключаем класс
require_once 'Mobile_Detect.php';
$detect = new Mobile_Detect;
 
if($detect->isMobile()){
     echo "контент для мобильных устройств";
}
 
if($detect->isTablet()){
     echo "контент для планшетов";
}
 
if(!$detect->isMobile() && !$detect->isTablet()){
     echo "контент для компов";
}
 
if($detect->isiOS()){
     echo "для iOS";
}
 
if($detect->isAndroidOS()){
     echo "для Android";
}
 
if($detect->is('UC Browser')){
     echo "таблетка для УС браузера";
}
таким образом можно использовать этот класс для различных целей
например
if($detect->isMobile()){
     echo "<link rel='stylesheet' href='mobile.css'>";
}

помогу с установкой обращайтесь в личку
всем спасибо за внимание hello

Site: Coolrow CoolCMS
Данный роутер не претендует на звание лучшего решения и пойдет сугубо новичкам как отталкивающий материал для создания своей системы роутера по сайту, но вполне рабочее решение которое можно применять в реальных проектах. Ну поехали.

Для начала добавим в файл .htaccess следующий код:
DirectoryIndex index.php
Options All -Indexes

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
С помощью этого кода делаем единую точку входа. Все наши запросы к сайту будут проходить через index.php.

Теперь пишем файл роутера назовем его допустим route.php и положим по адресу domaine.ru/core/route.php:
<?php
/* Константы - обычно задаются раньше чем в самом файле роутера */
define('CORE_DIRECTORY', __DIR__);

// Действия по умолчанию  
$application_name_default = 'main';  
$action_name_default = 'index';  

// Разбираем url на части  
$routes = explode('/', filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL));  

// Получаем имя приложения 
$application_name = !empty($routes[1]) ? $routes[1] : $application_name_default; 
// Получаем имя экшена 
$action_name = !empty($routes[2]) ? $routes[2] : $action_name_default;  

// Грузим приложение  
$application_path = CORE_DIRECTORY . '/application/'. strtolower($application_name . '/' . $action_name) . '.php';
if ( file_exists($application_path) )  
{  
    require $application_path;  
}  
else  
{  
    // Если неверное приложение то на главную  
    $application_path = CORE_DIRECTORY . '/application/'.$application_name_default.'/'.$action_name_default.'.php'; 
    require $application_path;  
}
При необходимости путь "CORE_DIRECTORY . '/application/" заменить на свой и поместить файл route.php куда нужно (а лучше использовать его как class).
Теперь ссылки делаем формата <a href="/chat/index">Чат<a> где "chat" это папка с файлами а "index" нужный файл.

Адрес типа domaine.ru/chat приведет к domaine.ru/core/application/chat/index.php
А адрес domaine.ru/chat/list приведет к domaine.ru/core/application/chat/list.php

Так же можно по простому передавать GET переменные:
domaine.ru/chat?page=2 и использовать "page" как обычную GET переменную (не забываем фильтровать при надобности).

Если будут вопросы прошу в ЛС =)
пишем такое в верху
анкеты,после вывода
ника.
$uzertime=substr($uzdata[18],0,5);$montime=date_fixed($sitetime,"d.m"); if($uzertime==$montime){echo'<div align="center"><font color="#FF0000"><b>Пользователь,отмечает день рождения!</b></font></div>';}
и получаем
Пользователь,отмечает
день рождения!
пишем вот такой код
if ($uzdata[18]!="" && $uzdata[18]!=".."){
echo'Дата Рождения: '.check($uzdata[18]).' ';
$expArr = explode('.', $uzdata[18]);
if(strlen($expArr[2])==2){
if($expArr[2]<30){  $expArr[2]='20'.$expArr[2];
}else{
$expArr[2]='19'.$expArr[2];}}
$years = date("Y") - $expArr[2];
if(date("d") < $expArr[1] AND date("m") < $expArr[0]){--$years;}
echo ' (<b>'.$years.'</b>)<br>';}
вырезав перед этим стандартный код вывода даты рождения.

P.S. В этом коде одна ячейка изменена,ранее он почему-то выводил,возраст исходя из месяца в ДР. При тестировании,возраст зависел от всех введёных данных.
Если при создании новости,вы удаляете первый коммент. То на странице комментариев можно добавить такой код
if(utf_strlen($dt[1])>100){ 
$dt[1]=substr($dt[1],0,250);
 echo'<font color="red">Новость:</font> '.bb_code($dt[1]).'... ';}
он отобразит часть новости,той,в комменты которой вы зашли.
Многие начинающие PHP разработчики сталкиваются с определеним страны по ip, в этой заметке я приведу один из вариантов её определения.
В данном примере мы будем работать с гео базой Smart-IP.net. Smart-IP предоставляет api, поэтому все, что нам необходимо будет сделать - послать запрос на сервер Smart-IP и обработать полученный результат.

Значения, которые мы можем получить:
countryName - Страна;
countryCode - Код страны (UA, RU...);
city - Город;
region - Регион;
latitude - Широта;
longitude - Долгота;

А теперь напишем функцию, которая будет определять название страны:
<?

function country($ip)
{
	$xml = simplexml_load_file('http://ru.smart-ip.net/geoip-xml/'.$ip);

	return $xml->countryName;
}

?>

Использование функции:
<?

echo country('93.79.81.58');

?>

На этом пожалуй все smile
Так как написанные системы по принципу mvc обрабатывают роутинг средствами php обнаружил уже давно такой баг как выполнение 2х запросов к сайту от одного пользователя при каждом обновлении страницы. Заметил это при написании онлайн счетчика который добавлял ip адрес в таблицу, а если он уже существовал то обновлял поле hits которое содержало количество хитов. При втором обновлении наблюдал в базе 3 хита, при третьем обновлении 5 хитов и т.д, значение счетчика хитов постоянно увеличивалось на 2. После тестов с логами, оказалось это из-за несуществующей иконки favicon в шапке.
В htaccess мы используем RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
таким образом, что первое есть в url он проверяет как файл или дирикторию, если не найдены, отправляет url запрос в index.php. При несуществующей favicon.ico создается второй запрос к сайту, вот собственно и причина двух запрос. Такая же ситуация возникнет при любой несуществующей картинки которая объявлена в разметке. Сегодня я снова столкнулся с этой проблемой и решил все же написать статью об этом. В этот раз заметил этот баг уже при отсутствии favicon на страницы, все так же выполнялось по два запроса к сайту при одном обновлении страницы, снова посмотрел лог и увидел запрос /favicon.ico, но она не была объявлена в шапке, после чего я ее объявил и все стало нормально работать. Как я понял chrome запрашивает иконку страницы по умолчанию site.ru/favicon.ico если она не была объявлена в head, может так делают и другие браузеры, не проверял.

Почему это плохо?
Сбой сессионных данных, два потока от одного пользователя. Если на сайт зайдет 100 человек, то выполнится не 100 запросов,а 200, а так же при серфе все это еще будет умножатся, это еще и лишние ресурсы сервера.

Вывод
Не оставляйте сайт без favicon иконки, вроде мелочь, а последствия серьезные
В некоторых случаях необходимые подгружаемые изображения могут не оказаться на сервере, поэтому стоит проверять функцией на существования, повторюсь в некоторых случаях, не призываю вас этого делать.
Облако тегов / Авторы