Демо - http://demobuh.skahin.ru
Пароль и логин: admin
Описание возможностей и онлайн использование: http://buh.skahin.ru
Разработка и исходный код: https://github.com/pihel/cash
Личный блог. Заметки о программировании и не только
<?php
//событие подключения визуального редактора
AddEventHandler("fileman", "OnIncludeHTMLEditorScript", array("MyHandlers", "OnIncludeHTMLEditorScript"));
class MyHandlers {
public static function OnIncludeHTMLEditorScript()
{
?>
<script type="text/javascript">
//получаем указатель на полотно визуального редактора
BXHTMLEditor.prototype.SetView_ = BXHTMLEditor.prototype.SetView;
BXHTMLEditor.prototype.SetView = function (sType) {
var result = this.SetView_(sType);
var html = undefined;
if(BX.browser.IsIE()) {
try {
html = this.pEditorDocument.body;
} catch (e) {
//
}
} else {
try {
html = this.pEditorWindow.document.body;
} catch (e) {
//
}
}
if( sType == "html" && html ) {
//обертываем в DIV, если его еще нет
if( html.innerHTML.indexOf('<div class="content">') == -1 ) {
html.innerHTML = '<div class="content">'+html.innerHTML+'</div>';
}
}
return result;
};
</script>
<?
}
}
?>
function getIblockProps($id) {
global $DB;
$sql = "SELECT b.id, b.code, b.name,
-----
p.id as pid, p.code as pcode, p.name as pname, p.SORT psort,
UPPER(CASE
WHEN p.USER_TYPE IS NOT NULL THEN p.USER_TYPE
WHEN p.PROPERTY_TYPE = 'S' AND p.ROW_COUNT > 1 THEN 'T'
ELSE p.PROPERTY_TYPE
END) as ptype,
CASE WHEN p.MULTIPLE = 'Y' THEN 1 END as pmultiple, CASE WHEN p.MULTIPLE = 'Y' THEN p.MULTIPLE_CNT END pmultiple_cnt,
CASE WHEN p.LINK_IBLOCK_ID > 0 THEN p.LINK_IBLOCK_ID END as piblock,
CASE WHEN p.IS_REQUIRED = 'Y' THEN p.IS_REQUIRED END preq, p.HINT as phint,
-----
e.ID as eid, e.VALUE as evalue, e.DEF as edef, e.SORT as esort
FROM b_iblock b , b_iblock_property p
LEFT JOIN b_iblock_property_enum e
ON(e.property_id = p.id)
WHERE b.id = %u
AND b.id = p.IBLOCK_ID AND p.ACTIVE = 'Y'
ORDER BY p.sort,e.SORT";
$rs = $DB->Query( sprintf( $sql, intval($id) ) );
$rows = array();
while ($row = $rs->Fetch()) {
$rows[] = $row;
}
return $rows;
}
$el = new CIBlockElement; $id = $el->Add($arFields);
CPrice::SetBasePrice( $id, $arFields['PRICE'], "RUB", 1);
$arFields = Array( "PRODUCT_ID" => $id, "STORE_ID" => 1, "AMOUNT" => $v['Количество'], ); CCatalogStoreProduct::Add($arFields);
$arFields = array('ID'=>$id, 'PRICE_TYPE' => 'S', 'QUANTITY' => floatval($f['Количество']));
CCatalogProduct::Add($arFields);
createFunction('UPPER_UTF8', 'upper_ru', 1);
//array('SQLITE_DB', 'upper_ru') - если используете в составе класса 'SQLITE_DB'
?>
После этих нехитрых манупуляций в составе SQLite появится новая функция UPPER_UTF8 и с помощью ее можно будет делать регистронезависимые запросы:
SELECT
t.*
FROM
table t
WHERE
UPPER_UTF8(t.col) LIKE UPPER_UTF8('%кАкойТо Запрос%')
--таблица
CREATE TABLE "cashes" (
"id" INTEGER PRIMARY KEY NOT NULL,
"date" DATE NOT NULL,
"uid" INT(10) NOT NULL DEFAULT ('1'),
"visible" TINYINT(4) NOT NULL DEFAULT ('1')
);
--индекс
CREATE INDEX "XIF_CASHES_DUV" on cashes (date DESC, uid ASC, visible ASC);
--вызов плана
EXPLAIN QUERY PLAN SELECT
c.id, c.uid, c.date
FROM cashes c
WHERE
c.date BETWEEN '2013-04-01' AND '2013-06-01'
AND c.uid = 1 AND c.visible = 1
ORDER BY
c.date;
--план
SEARCH TABLE cashes AS c USING INDEX XIF_CASHES_USR (uid=?) (~2 rows)
А дальше, как нужно было правильно создавать индекс. Поле даты - поле диапозона, должно было идти последним:
--индекс CREATE INDEX "XIF_CASHES_DUV" on cashes (uid ASC, visible ASC, date DESC); --план запроса SEARCH TABLE cashes AS c USING INDEX XIF_CASHES_DUV (uid=? AND visible=? AND date>? AND date<?) (~42 rows)Причем если бы мы искали точное соответствие по дате, то сработали бы оба индекса, но при поиске по диапазону только последний.
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", Array("MyClass", "OnBeforeIBlockElementUpdateHandler"));
class MyClass
{
function OnBeforeIBlockElementUpdateHandler(&$arFields)
{
$arFields["DETAIL_TEXT"] = str_replace('src="../../upload/', 'src="/upload/', $arFields["DETAIL_TEXT"]);
}
}
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", Array("MyClass", "OnBeforeIBlockElementUpdateHandler"));
class MyClass
{
function OnBeforeIBlockElementUpdateHandler(&$arFields)
{
if(!empty($arFields["DETAIL_TEXT"])) {
$arFields["DETAIL_TEXT"] = str_replace('src="../../upload/', 'src="/upload/', $arFields["DETAIL_TEXT"]);
}
}
}
<?
//событие загрузки визуального редактора
AddEventHandler("fileman", "OnIncludeHTMLEditorScript", "OnIncludeHTMLEditorHandler");
//наш обработчик
function OnIncludeHTMLEditorHandler()
{
?>
<script>
//запоминаем ссылку на родителя
SAttr_= SAttr;
SAttr = function (e,a,v) { //элемента, свойство, значение
//выполняем сначала родителя (устанавливаем свойства)
this.SAttr_(e,a,v);
//произошла установка title изображения
//title может быть установлен при изменении или загрузке изображения
if(a == 'title' && e.tagName == 'IMG') {
var src = e.src;
//формируем новое изображение
var img = '';
if(e.hspace > 0) img = img + ' hspace='+e.hspace;
if(e.vspace> 0) img = img + ' vspace='+e.vspace;
if(e.border> 0) img = img + ' border='+e.border;
if(e.align != "") img = img + ' align="'+e.align+'"';
//if(e.alt!= "") img = img + ' alt="'+e.alt+'"';
if(e.title!= "") img = img + ' title="'+e.title+'"';
//вставляем наше измененное изображение
//я использовал плагин zoomie для jquery, без собственно ресайза изображения
pObj.pMainObj.insertHTML('<img alt="'+src+'" class="zoomi" width='+e.width+' height='+e.height+' src="'+src+'" '+img+'>');
//удаляем неизмененное изображение
e.parentNode.removeChild(e);
}
}
</script>
<?
}
?>
Не так давно Vkontakte ввело возможность разработки iFrame приложений. В связи с этим у многих разработчиков встал вопрос как защитить данные, передаваемые между приложением и api.
method=getProfiles&uids={viewer_id}&format=json&v=2.0
Тем самым мы получаем несколько параметров, один из которых нужный нам - viewer_id, а также сигнатуру данных (auth_key), подписанных секретным ключом, который гарантирует нам верность данных.
function secureSend(_data, _callback) {
$.ajax({
type: "POST",
url: "ajax.php",
data: (_data),
dataType: "json",
success: function(data) {
if(data.error != undefined) {
error(data.error);
return false;
} else {
_callback(data.response);
}
}
});
}
На сервере же расположить скрипт обрабатывающий только обращения к API, которые пересылают данные от пользователя к серверу. Разрешить можно все действия, т.к. пользователя мы проверили на предыдущем этапе и уже тут он волен сколько угодно раз пересылать свои голоса к приложению :)
$vk_allow_methods = array("secure.withdrawVotes", "secure.getBalance");
$q = $_POST;
$d = "";
if(in_array($q['method'], $vk_allow_methods)) {
$d = vkSend($q['method']);
}
function vkSend($method) {
$server = "http://api.vkontakte.ru/api.php?";
$key = "000";
$aid = 1;
$qr = array();
$qr[] = 'method='.$method;
$qr[] = 'api_id='.$aid;
$qr[] = 'v=2.0';
$qr[] = 'format=JSON';
$qr[] = 'timestamp='.time();
$qr[] = 'random='.rand(1, 999999);
$qr[] = 'test_mode=1';
sort($qr);
$url4sign = implode("", $qr).$key;
$sign = md5($url4sign);
$url = implode("&", $qr)."&sig=".$sign;
return file_get_contents($server.$url);
}
echo $d;
В ходе построения клиент-серверного приложения, требуется реализовать возможность защищенной передачи данных.var key:String = "0000-0000-0000-0000-0000";
var sreq:String = "method=setBalance&addMoney=1000"; //сам запрос
//отсортируем параметры
//чтобы последовательность параметром и на клиенте и на сервере была одинакова. Это гарантирует схождение хэшей.
sreq = sreq.split("&").sort().join("&");
//добавим к параметрам время, чтобы нельзя было продублировать запрос
var now:Date = new Date();
var sec = now.getTime().toString().substr(0, -3);
//конечный запрос к серверу с дополнительным параметром = хэшу запроса и секретного ключа
sreq = sreq + "×tamp="+sec+"&sig="+MD5.hash(sreq+key);
c. Сервер принимает запрос и проверяет данные используя свой секретный ключ.$_TIME = $_SERVER['REQUEST_TIME'];//время запроса
$_KEY = "0000-0000-0000-0000-0000";//тотже ключ, что и на клиенте
$_TIMEOUT = 100; //допустимое отклонение времени
// Проверим валидность данных
//присланная подпись должна сойтись со сгенерированной на основе закрытого ключа
$q = $_GET;
//отсортируем также как в flex
unset($q['timestamp'], $q['sig']);
ksort($q);
$req = "";
foreach($q as $k=>$v) {
$req .= $k."=".$v."&";
}
$req = substr($req, 0, -1);
if($_GET['sig'] != md5($req.$_KEY)) {
//подписи не сошлись. Данные были подменены.
exit;
}
//Проверим расхождение времени
if($_GET['timestamp'] + $_TIMEOUT < $_TIME) {
//Расхождение более чем на 100 секунд. Прерываем запрос
exit;
}
$node['punbb'] == array('id', //ид топика
'subject', //тема топика
'posted', //автор топика
'url'); //url до топика на форуме
function getCOde() {
$code = sprintf("%06x", rand(1000000, 10000000)); //рандомное число, преобразованное в hex
//проверяем на повторения
$res = db_query("SELECT COUNT(*) AS cnt FROM {sms_pay} WHERE code = '%s'", $code);
$codes = db_fetch_array($res);
if($codes['cnt'] > 0) {
getCode(); //генерируем еще раз
}
db_query("INSERT INTO {sms_pay} (code) VALUES('%s')", rand(), $code); //записываем код в БД
return $code;
}
Сгенерированный код, вываливается через echo в браузер, а сервер весь сгенерированый текст отправляет в виде смс обратно клиенту.
$r = $sp->query("insert into ?_url_alias(src, dst) VALUES(%s, %s)", "tst", "test");
echo $sp->query("update ?_url_alias set dst = %s where pid = %u", "tst1", $r);
print_r($sp->selectCol("{?_url_alias} select * from ?_url_alias"));
print_r($sp->selectRow("{?_url_alias} select * from ?_url_alias where pid = %u and dst = %s", 1, "news"));
print_r($sp->select("select * from ?_url_alias"));
Возможности: плэйсхолдеры, кэширование, перфиксы таблиц, выборка таблиц/строк/ячеек/столбцов Read Template and set Variables ->getTpl(string Tpl [, mixed Variable1 [, mixed Variable2] [, ...]]); return: String template with replace variables. Exit program, if template not existДата разработки: июль 2008