Welcome to Bitrix Notes!

Contents:

single: Recipes for common tasks

Recipes for common tasks

This section contains scripts for common tasks often found in work with Bitrix

Loop for all elements in iblock

Getlist sorted by TIMESTAMP_X asc and limited by 1000 elements.

<?php
CModule::IncludeModule('iblock');
$arSelect = array('ID', 'NAME', 'CODE');
$arFilter = array('IBLOCK_ID' => 10, 'ACTIVE' => 'Y');
$res = CIBlockElement::GetList(
    array('TIMESTAMP_X' => 'ASC'),
    $arFilter,
    false,
    array('nPageSize' => 1000),
    $arSelect
);
while ($ob = $res->GetNextElement()) {
    $arFields = $ob->GetFields();

}

Include section

<?$APPLICATION->IncludeFile(
     $APPLICATION->GetTemplatePath("/include/logo.php"),
     Array(),
     Array("MODE"=>"php")
);?>

<?$APPLICATION->IncludeComponent(
    "bitrix:main.include",
    "sidebar",
    Array(
        "AREA_FILE_SHOW" => "sect",
        "AREA_FILE_SUFFIX" => "inc",
        "AREA_FILE_RECURSIVE" => "N",
        "EDIT_MODE" => "html",
    ),
    false,
    Array('HIDE_ICONS' => 'Y')
);?>

Delete offers without photos

<?php
CModule::IncludeModule('iblock');
$arSelect = array('ID', 'DETAIL_PICTURE', 'PREVIEW_PICTURE');
$arFilter = array('IBLOCK_ID' => 9, 'ACTIVE' => 'Y');
$res = CIBlockElement::GetList(
    array('TIMESTAMP_X' => 'ASC'),
    $arFilter,
    false,
    array('nPageSize' => 1000),
    $arSelect
);
while ($ob = $res->GetNextElement()) {
    $arFields = $ob->GetFields();
    $bNoPics = false;

    if (empty($arFields['PREVIEW_PICTURE']) && empty($arFields['DETAIL_PICTURE'])) {
        $bNoPics = true;
    }

    if ($bNoPics) {
        $arSelect2 = array('ID', 'PROPERTY_CML2_LINK');
        $arFilter2 = array('IBLOCK_ID' => 13, 'PROPERTY_CML2_LINK' => $arFields['ID']);
        $res2 = CIBlockElement::GetList(
            array('TIMESTAMP_X' => 'ASC'),
            $arFilter2,
            false,
            array('nPageSize' => 1),
            $arSelect2
        );
        while ($ob2 = $res2->GetNextElement()) {
            $arFields2 = $ob2->GetFields();
            CIBlockElement::Delete($arFields2['ID']);
        }

    }
}

Update all prices

<?php
CModule::IncludeModule('catalog');

$db_res = CPrice::GetList(
    array(),
    array(
        'CURRENCY' => 'RUB'
    )
);
while ($ar_res = $db_res->Fetch()) {
    CPrice::Update($ar_res["ID"], ['CURRENCY' => 'UAH']);
}

Detect mobile regex

<?php
$useragent=$_SERVER['HTTP_USER_AGENT'];
if(preg_match('/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))) {
    header('Location: http://m.site.ru '.$APPLICATION->GetCurPageParam());
}

Build table with all products

<?php
require($_SERVER["DOCUMENT_ROOT"] . '/bitrix/modules/main/include/prolog_before.php');
\Bitrix\Main\Loader::includeModule('iblock');

$arSelect = array('ID', 'NAME', 'CODE', 'ACTIVE');
$arFilter = array('IBLOCK_ID' => CATALOG_IBLOCK, 'ACTIVE' => 'Y');
$res = CIBlockElement::GetList(
    array(),
    $arFilter,
    false,
    false,
    $arSelect
);
?>
<table>
    <tr>
        <td>ID</td>
        <td>Название</td>
        <td>Символьный код</td>
        <td>Активность</td>
    </tr>
    <?php while ($arFields = $res->GetNext()) {
        ?>
        <tr>
            <td><?= $arFields['ID'] ?></td>
            <td><?= $arFields['NAME'] ?></td>
            <td><?= $arFields['CODE'] ?></td>
            <td><?= $arFields['ACTIVE'] ?></td>
        </tr>
        <?php
    }
    ?>
</table>

Read large CSV file

$ composer require league/csv:^8.0
<?php
require_once '/vendor/autoload.php';
use League\Csv\Reader;

set_time_limit(0);
ini_set('display_errors', 1);

$importStep = 1000;
$importStart = 0;

$csv = Reader::createFromPath(__DIR__.'/your.csv');
$csv->setDelimiter('|')
    ->setOffset($importStart)
    ->setLimit($importStep);

$csv->each(function ($row, $rowOffset) {
    var_dump($row);

    return true;
});

Write CSV file

$ composer require league/csv:^8.0
<?php
use Bitrix\Main\Application;
use League\Csv\Writer;

$root = Application::getDocumentRoot();

$writer = Writer::createFromPath($root.'/upload/your.csv', 'w');
$writer->setDelimiter(';');
$writer->insertOne(['col1', 'col2']);

foreach ($data as $item) {
    $writer->insertOne([$item['field1'], $item['field2']]);
}

Caching example

D7 style

<?php
use \Bitrix\Main\Data\Cache;

$cache = Cache::createInstance();
if ($cache->initCache(7200, "cache_key")) {
    $vars = $cache->getVars();
}
elseif ($cache->startDataCache()) {
    $cache->endDataCache(array("key" => "value"));
}

//public function initCache($TTL, $uniqueString, $initDir = false, $baseDir = "cache")

Managed cache

<?php
$cache = \Bitrix\Main\Application::getInstance()->getManagedCache();

if ($cache->read($cacheTtl, $cacheId)) {
    $vars = $cache->get($cacheId);
} else {
    $cache->set($cacheId, array("key" => $value));
}

//clear by tag
$cache->clean($cacheId);

Old style

<?php
$cache = new CPHPCache;
$cache_time = 3600;
$cache_id = 'cache_id';
if ($cache->InitCache($cache_time, $cache_id, '/' . SITE_ID . '/cache/path/')) {
    $arVars = $cache->GetVars();
    return $arVars['DATA'];
} else {
    $cache->StartDataCache($cache_time, $cache_id);

    //get your data
    $data = 'some_text';

    if ($data) {
        $cache->EndDataCache(['DATA' => $data]);
        return $data;
    } else {
        return false;
    }
}

Get Iblock id by it’s code

<?php
/**
 * Returns Iblock ID by it's code
 *
 * @param $iblockCode
 * @return bool
 */
function getIblockIdByCode($iblockCode)
{
    $cache = new CPHPCache;
    $cache_time = 3600;
    $cache_id = 'get_id_'.$iblockCode;
    if ($cache->InitCache($cache_time, $cache_id, '/'.SITE_ID.'/iblock/helper/')) {
        $arVars = $cache->GetVars();
        return $arVars['DATA']['ID'];
    } else {
        $cache->StartDataCache($cache_time, $cache_id);

        $arIblock = IblockTable::getList([
            'filter' => ['CODE' => $iblockCode],
            'select' => ['ID']
        ])->fetch();

        if ($arIblock) {
            $cache->EndDataCache(['DATA' => $arIblock]);
            return $arIblock['ID'];
        } else {
            return false;
        }
    }
}

Admin section recipes

Add custom page in admin section

Add new folder under your local folder

$ mkdir local/bitrix.admin

Update urlrewrite.php file - add new rule

<?
$arUrlRewrite = array(
    // ...
    array(
        'CONDITION' => '#^/bitrix/admin/(.*)#',
        'RULE' => '/local/bitrix.admin/$1',
        'ID' => '',
        'PATH' => '',
    ),
    // ...
);

Admin page example. Place it in local/bitrix.admin folder

<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/sale/include.php';

/** @var CMain $APPLICATION */
$saleModulePermissions = $APPLICATION->GetGroupRight('sale');

/** @var CUser $USER */
if (!$USER->IsAdmin()) {
    $APPLICATION->AuthForm(GetMessage('ACCESS_DENIED'));
}

IncludeModuleLangFile(__FILE__);

$APPLICATION->SetTitle('Настройки eSputnik');

require $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_after.php';
?>
<?php
$moduleName = 'esputnik';
$settings = array(
    array(
        'LABEL' => 'Логин',
        'FORM_NAME' => 'esp-login',
        'OPTION_NAME' => 'LOGIN',
    ),
    array(
        'LABEL' => 'Пароль',
        'FORM_NAME' => 'esp-password',
        'TYPE' => 'password',
        'OPTION_NAME' => 'PASSWORD',
    ),
);
if (isset($_REQUEST['save']) && strlen($_REQUEST['save']) > 0) {
    foreach ($settings as $setting) {
        if (isset($_REQUEST[$setting['FORM_NAME']])) {
            COption::SetOptionString($moduleName, $setting['OPTION_NAME'], $_REQUEST[$setting['FORM_NAME']]);
        }
    }
}
?>
    <style>
        .form-group {
            display: block;
            margin: 3px;
        }
        .form-group > label {
            display: inline-block;
            min-width: 200px;
        }
    </style>
    <form method="POST" action="<?= $APPLICATION->GetCurUri()?>">
        <?php foreach ($settings as $setting) :?>
            <div class="form-group" title="<?=$setting['DESCRIPTION']?>">
                <label for="<?=$setting['FORM_NAME']?>"><?=$setting['LABEL']?>:</label>
                <input type="<?=$setting['TYPE']?:'text'?>"
                       name="<?=$setting['FORM_NAME']?>" id="<?=$setting['FORM_NAME']?>"
                       value="<?=COption::getOptionString($moduleName, $setting['OPTION_NAME']);?>"
                       placeholder="<?=$setting['DESCRIPTION']?>"
                >
            </div>
        <?php endforeach;?>
        <div class="form-group">
            <input type="submit" class="adm-btn" name="save" title="Сохранить" value="Сохранить">
        </div>
    </form>
<?php
require $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php';

Add new admin menu item

AddEventHandler('main', 'OnBuildGlobalMenu', 'addMenuItem');

function OnBuildGlobalMenuHandler(&$adminMenu, &$moduleMenu)
{
    global $USER;
    if($USER->IsAdmin())
    {
        $moduleMenu[] = array(
            'parent_menu' => 'global_menu_store',
            'sort' => 10,
            'url' => 'your_new_page.php?lang='.LANG,
            'text' => 'your_new_page',
            'title' => 'your_new_page',
            'icon' => 'fav_menu_icon',
            'page_icon' => 'fav_menu_icon',
            'items_id' => 'menu_order',
        );
    }
}

Custom order page

Info bar

<?php
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler('sale', 'onSaleAdminOrderInfoBlockShow', 'onSaleAdminOrderInfoBlockShow');

function onSaleAdminOrderInfoBlockShow(\Bitrix\Main\Event $event)
{
    $order = $event->getParameter("ORDER");
    //$basket = $event->getParameter("ORDER_BASKET");

    $propertyCollection = $order->getPropertyCollection();
    $location = \Bitrix\Sale\Location\Admin\LocationHelper::getLocationStringByCode($propertyCollection->getDeliveryLocation()->getValue());

    return new \Bitrix\Main\EventResult(
        \Bitrix\Main\EventResult::SUCCESS,
        array(
            array(
                'TITLE' => 'Местоположение:',
                'VALUE' => $location,
                'ID' => 'location'
            ),
        )
    );
}

Tabs

<?php
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler("main", "OnAdminSaleOrderView", array("MyAdminOrderFormTabs", "onInit"));

class MyAdminOrderFormTabs
{
    function onInit()
    {
        return array(
            "TABSET" => "MyTabs",
            "GetTabs" => array("MyAdminOrderFormTabs", "getTabs"),
            "ShowTab" => array("MyAdminOrderFormTabs", "showTabs"),
            "Action" => array("MyAdminOrderFormTabs", "onSave"),
            "Check" => array("MyAdminOrderFormTabs", "onBeforeSave"),
        );
    }

    function getTabs($args)
    {
        return array(
            array(
                "DIV" => "myTab1",
                "TAB" => "New Tab",
                "TITLE" => "New Tab Title",
                "SORT" => 1
            )
        );
    }

    function showTabs($tabName, $args, $varsFromForm)
    {
        if ($tabName == "myTab1") {
            echo "Tab Content";
        }
    }

    function onBeforeSave($args)
    {
        return true;
    }

    function onSave($args)
    {
        return true;
    }
}

Set price extra for all products

<?php
function setGlobalPriceExtra()
{
    $arSelect = ['ID', 'NAME'];
    $arFilter = ['IBLOCK_ID' => OFFERS_IBLOCK_ID,];
    $resOffer = CIBlockElement::GetList(
        [],
        $arFilter,
        false,
        ['nPageSize' => 5000],
        $arSelect
    );
    $el = new CIBlockElement;
    global $USER;

    \Bitrix\Main\Diag\Debug::dump($resOffer->SelectedRowsCount());
    \Bitrix\Main\Diag\Debug::dump('===========');

    while ($arFieldsOffer = $resOffer->GetNext()) {
        $arFields = array(
            "PRODUCT_ID" => $arFieldsOffer['ID'],
            "CATALOG_GROUP_ID" => 4,
            "EXTRA_ID" => 1,
            "CURRENCY" => "RUB",
        );

        $res = CPrice::GetList(
            array(),
            array(
                "PRODUCT_ID" => $arFieldsOffer['ID'],
                "CATALOG_GROUP_ID" => 4
            )
        );

        if ($arr = $res->Fetch()) {
            \Bitrix\Main\Diag\Debug::dump(CPrice::Update($arr["ID"], $arFields));
        } else {
            \Bitrix\Main\Diag\Debug::dump(CPrice::Add($arFields));
        }

        $arLoadProductArray = array(
            "MODIFIED_BY" => $USER->GetID(),
            "TIMESTAMP_X" => ConvertTimeStamp(time(), 'FULL')
        );
        $el->Update($arFieldsOffer['ID'], $arLoadProductArray);
    }
}

Send instant message to users

<?php
CModule::IncludeModule("socialnetwork");
$arFields = array(
    "FROM_USER_ID" => 2,
    "TO_USER_ID" => 1,
    "MESSAGE" => "Youк message",
    "=DATE_CREATE" => $GLOBALS["DB"]->CurrentTimeFunction(),
    "MESSAGE_TYPE" => "S",
);
CSocNetMessages::Add($arFields);

Recipes for work with orders

This section contains scripts for common tasks often found in work with orders

Get order props

<?php
\Bitrix\Main\Loader::includeModule('sale');

//get needed order properties
$db_vals = CSaleOrderPropsValue::GetList(
    array('SORT' => 'ASC'),
    array(
        'ORDER_ID' => $ORDER_ID,
        'CODE' => array(
            'PROP_CODE',
            'PROP_CODE_1',
        ),
    ),
    false,
    false,
    array(
        'VALUE',
        'CODE'
    )
);
while ($arVals = $db_vals->Fetch()) {

}

Copy order

This function shows how you can copy order by it’s ID. This function do NOT copies basket properties

<?php
/**
 * Make copy of order with $orderId. Increments value of COPIED_ORDERS_COUNT order property
 * @param $orderId
 */
function doCopyOrder($orderId)
{
    \Bitrix\Main\Loader::includeModule('sale');

    $arOrder = CSaleOrder::GetByID($orderId);

    $newOrderPrice = $arOrder['PRICE'];

    $arNewOrderFields = array(
        'LID' => $arOrder['LID'],
        'PERSON_TYPE_ID' => $arOrder['PERSON_TYPE_ID'],
        'PAYED' => 'N',
        'CANCELED' => 'N',
        'STATUS_ID' => 'N',
        'EMP_STATUS_ID' => 1,
        'PRICE_DELIVERY' => $arOrder['PRICE_DELIVERY'],
        'ALLOW_DELIVERY' => 'N',
        'PRICE' => round($newOrderPrice, 0, PHP_ROUND_HALF_DOWN),
        'CURRENCY' => $arOrder['CURRENCY'],
        'DISCOUNT_VALUE' => $arOrder['DISCOUNT_VALUE'],
        'USER_ID' => $arOrder['USER_ID'],
        'PAY_SYSTEM_ID' => $arOrder['PAY_SYSTEM_ID'],
        'DELIVERY_ID' => $arOrder['DELIVERY_ID'],
        'USER_DESCRIPTION' => $arOrder['USER_DESCRIPTION'],
        'ADDITIONAL_INFO' => $arOrder['ADDITIONAL_INFO'],
        'COMMENTS' => 'Order copy',
        'TAX_VALUE' => $arOrder['TAX_VALUE'],
        'AFFILIATE_ID' => $arOrder['AFFILIATE_ID'],
    );

    $newOrderId = CSaleOrder::Add($arNewOrderFields);

    if ($newOrderId) {
        //copy needed order properties
        $db_vals = CSaleOrderPropsValue::GetList(
            array('SORT' => 'ASC'),
            array('ORDER_ID' => $orderId),
            false,
            false,
            array()
        );
        while ($arVals = $db_vals->Fetch()) {
            unset($arVals['ID']);
            $arVals['ORDER_ID'] = $newOrderId;

            CSaleOrderPropsValue::Add($arVals);
        }

        //copy order basket items
        $dbBasket = CSaleBasket::GetList(
            array('ID' => 'ASC'),
            array('ORDER_ID' => $orderId),
            false,
            false,
            array(
                'SET_PARENT_ID', 'TYPE', 'ID',
                'PRODUCT_ID', 'PRODUCT_PRICE_ID', 'PRICE', 'CURRENCY', 'WEIGHT', 'QUANTITY', 'LID',
                'NAME', 'CALLBACK_FUNC', 'MODULE', 'NOTES', 'PRODUCT_PROVIDER_CLASS', 'CANCEL_CALLBACK_FUNC',
                'ORDER_CALLBACK_FUNC', 'PAY_CALLBACK_FUNC', 'DETAIL_PAGE_URL', 'CATALOG_XML_ID', 'PRODUCT_XML_ID',
                'VAT_RATE'
            )
        );

        $item = new \CSaleBasket;
        while ($arBasket = $dbBasket->Fetch()) {
            if (\CSaleBasketHelper::isSetItem($arBasket)) {
                continue;
            }

            $arFields = array(
                'ORDER_ID' => $newOrderId,
                'PRODUCT_ID' => $arBasket['PRODUCT_ID'],
                'PRODUCT_PRICE_ID' => $arBasket['PRODUCT_PRICE_ID'],
                'PRICE' => $arBasket['PRICE'],
                'CURRENCY' => $arBasket['CURRENCY'],
                'WEIGHT' => $arBasket['WEIGHT'],
                'QUANTITY' => $arBasket['QUANTITY'],
                'LID' => $arBasket['LID'],
                'NAME' => $arBasket['NAME'],
                'CALLBACK_FUNC' => $arBasket['CALLBACK_FUNC'],
                'MODULE' => $arBasket['MODULE'],
                'NOTES' => $arBasket['NOTES'],
                'PRODUCT_PROVIDER_CLASS' => $arBasket['PRODUCT_PROVIDER_CLASS'],
                'CANCEL_CALLBACK_FUNC' => $arBasket['CANCEL_CALLBACK_FUNC'],
                'ORDER_CALLBACK_FUNC' => $arBasket['ORDER_CALLBACK_FUNC'],
                'PAY_CALLBACK_FUNC' => $arBasket['PAY_CALLBACK_FUNC'],
                'DETAIL_PAGE_URL' => $arBasket['DETAIL_PAGE_URL'],
                'CATALOG_XML_ID' => $arBasket['CATALOG_XML_ID'],
                'PRODUCT_XML_ID' => $arBasket['PRODUCT_XML_ID'],
                'VAT_RATE' => $arBasket['VAT_RATE'],
                'PROPS' => array(),
                'TYPE' => $arBasket['TYPE']
            );

            $item->Add($arFields);
        }
    }
}

Get basket props

<?php
/**
 * Function obtains all properties of a basket item
 * @param int $id Basket item Id to search for
 * @return mixed[] List of basket item properties
 */
protected function getBasketItemProps($id)
{
    \Bitrix\Main\Loader::includeModule('sale');

    $arProps = array();
    $dbBasketProps = CSaleBasket::GetPropsList(
        array("SORT" => "ASC"),
        array("BASKET_ID" => $id),
        false,
        false,
        array("ID", "BASKET_ID", "NAME", "VALUE", "CODE", "SORT")
    );

    if ($arBasketProps = $dbBasketProps->Fetch())
    {
        do
        {
            $arProps[] = array(
                "NAME" => $arBasketProps["NAME"],
                "CODE" => $arBasketProps["CODE"],
                "VALUE" => $arBasketProps["VALUE"]
            );
        }
        while ($arBasketProps = $dbBasketProps->Fetch());
    }

    return $arProps;
}

Recipes for SEO tasks

This section contains scripts for common SEO tasks

301 Redirect from old URL

Save current URL into property

<?php
CModule::IncludeModule('iblock');
$arSelect = array('ID', 'NAME', 'CODE', 'DETAIL_PAGE_URL', 'ACTIVE');
$arFilter = array('IBLOCK_ID' => 4);
$res = CIBlockElement::GetList(
    array('TIMESTAMP_X' => 'ASC'),
    $arFilter,
    false,
    array('nPageSize' => 1000),
    $arSelect
);
while ($ob = $res->GetNextElement()) {
    $arFields = $ob->GetFields();
    CIBlockElement::SetPropertyValuesEx(
        $arFields['ID'],
        false,
        array('OLD_URL' => $arFields['DETAIL_PAGE_URL'])
    );
}

Release redirect logic in init.php

<?php
AddEventHandler('main', 'OnBeforeProlog', 'MyOnBeforePrologHandler');

function MyOnBeforePrologHandler()
{
    global $APPLICATION;
    $curPage = 'http://example.com' . $APPLICATION->GetCurPage();
    if ($newUrl = getNewUrlFromOld($curPage, 2)) {
        LocalRedirect($newUrl, false, '301 Moved permanently');
    }
    if ($newUrl = getNewUrlFromOld($curPage, 1)) {
        LocalRedirect($newUrl, false, '301 Moved permanently');
    }
}

/**
 * returns a new url from an old stored in IBLOCK element/section property 'OLD_URL'/'UF_OLD_URL'
 * or false if no such element/section in IBLOCK
 * @param string $oldUrl
 * @param integer $iBlockId
 * @param string $elementFieldName (optional)
 * @param string $sectionFieldName (optional)
 * @return mixed
 */
function getNewUrlFromOld($oldUrl, $iBlockId, $elementFieldName = 'OLD_URL', $sectionFieldName = 'UF_OLD_URL')
{
    if (CModule::IncludeModule('iblock')) {
        $elementList = CIBlockElement::GetList(
            array('SORT' => 'ASC'),
            array(
                'IBLOCK_ID' => $iBlockId,
                'PROPERTY_' . $elementFieldName => $oldUrl
            ),
            false,
            false,
            array(
                'DETAIL_PAGE_URL'
            )
        );
        if ($arElement = $elementList->GetNext()) {

            return $arElement['DETAIL_PAGE_URL'];
        }
        $sectionList = CIBlockSection::GetList(
            array('SORT' => 'ASC'),
            array(
                'IBLOCK_ID' => $iBlockId,
                $sectionFieldName => $oldUrl
            ),
            false,
            array(
                'SECTION_PAGE_URL'
            )
        );
        if ($arSection = $sectionList->GetNext()) {

            return $arSection['SECTION_PAGE_URL'];
        }
    }
    return false;
}

Find and fix sections duplicates

For all section codes duplicates concat section code of it’s parent

<?php
CModule::IncludeModule('iblock');

$arFilter = array('IBLOCK_ID' => 4);
$by = 'ID';
$order = 'ASC';
$db_list = CIBlockSection::GetList(array($by => $order), $arFilter, false);
while ($ar_result = $db_list->GetNext()) {
    $arSect[] = $ar_result;
    $arCode[] = $ar_result['CODE'];
}

$arCodes = array_count_values($arCode);

foreach ($arCodes as $key => $arCd) {
    if ($arCd > 1) {
        $arEndCode[] = $key;
    }
}

foreach ($arSect as $arSection) {
    if (in_array($arSection['CODE'], $arEndCode)) {
        $resa = CIBlockSection::GetByID($arSection['IBLOCK_SECTION_ID']);
        if ($ar_resf = $resa->GetNext()) {
            $name = $ar_resf['CODE'];
        }

        $code = $name . '-' . $arSection['CODE'];

        $bs = new CIBlockSection;

        $arFields = array(
            'CODE' => $code,
        );

        $res = $bs->Update($arSection['ID'], $arFields);
    }
}

.htaccess SEO redirects

#remove index.(php|html|htm)
RewriteRule ^(.*)\/index\.(php|html?)$ /$1/ [R=301,NC,L]
RewriteRule ^index\.(php|html?)$ / [R=301,NC,L]

#www. to no www
RewriteCond %{SERVER_PORT}s ^(443(s)|[0-9]+s)$
RewriteRule ^(.*)$ - [env=askapache:%2]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http%{ENV:askapache}://%1/$1 [R=301,L]

#add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)(?:\/|\.html?|\.php)$
RewriteRule ^(.*)$ %{REQUEST_URI}/ [R=301,L]

Fix pictures URL changing

<?php

AddEventHandler('iblock', 'OnBeforeIBlockElementUpdate', 'checkImagesSize');

/**
 * Restrict image update if same image size given
 * @param $arFields
 */
function checkImagesSize(&$arFields)
{
    $arImageInfoDetail = \CFile::MakeFileArray($arFields['DETAIL_PICTURE']['old_file']);
    if ($arFields['DETAIL_PICTURE']['size'] == $arImageInfoDetail['size']) {
        unset($arFields['DETAIL_PICTURE']);
    }

    $arImageInfoPreview = \CFile::MakeFileArray($arFields['PREVIEW_PICTURE']['old_file']);
    if ($arFields['PREVIEW_PICTURE']['size'] == $arImageInfoPreview['size']) {
        unset($arFields['PREVIEW_PICTURE']);
    }
}

Change elements code separator from ‘_’ to ‘-‘

<?php
CModule::IncludeModule('iblock');
$arSelect = array('ID', 'NAME', 'CODE');
$arFilter = array('IBLOCK_ID' => 10, 'ACTIVE' => 'Y');
$res = CIBlockElement::GetList(
    array('TIMESTAMP_X' => 'ASC'),
    $arFilter,
    false,
    array('nPageSize' => 1000),
    $arSelect
);
while ($ob = $res->GetNextElement()) {
    $arFields = $ob->GetFields();
    $newCode = str_replace('_', '-', $arFields['CODE']);

    $el = new CIBlockElement;

    $arLoadProductArray = array(
        'MODIFIED_BY' => $USER->GetID(),
        'CODE' => $newCode,
    );

    $res2 = $el->Update($arFields['ID'], $arLoadProductArray);
}

Change sections code separator from ‘_’ to ‘-‘

<?php
CModule::IncludeModule("iblock");
$arFilter = array("IBLOCK_ID" => 11);
$db_list = CIBlockSection::GetList(array(), $arFilter, true);
while ($ar_result = $db_list->GetNext()) {
    $newCode = str_replace("_", "-", $ar_result["CODE"]);

    $bs = new CIBlockSection;
    $arFields = array(
        "CODE" => $newCode,
    );

    $res = $bs->Update($ar_result["ID"], $arFields);
}

Common event handlers

This section contains common Bitrix event handlers

Minimal and maximal price props

<?php

AddEventHandler('iblock', 'OnAfterIBlockElementAdd', 'DoIBlockAfterSave');
AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'DoIBlockAfterSave');
AddEventHandler('catalog', 'OnPriceAdd', 'DoIBlockAfterSave');
AddEventHandler('catalog', 'OnPriceUpdate', 'DoIBlockAfterSave');

/**
 * Runs on events:
 * - OnAfterIBlockElementAdd
 * - OnAfterIBlockElementUpdate
 * - OnPriceAdd
 * - OnPriceUpdate
 *
 * Calculates min and max prices and saves them into propd
 * @param      $arg1
 * @param bool $arg2
 */
function DoIBlockAfterSave($arg1, $arg2 = false)
{
    $ELEMENT_ID = false;
    $IBLOCK_ID = false;
    $OFFERS_IBLOCK_ID = false;
    $OFFERS_PROPERTY_ID = false;

    //Check for catalog event
    if (is_array($arg2) && $arg2["PRODUCT_ID"] > 0) {
        //Get iblock element
        $rsPriceElement = CIBlockElement::GetList(
            array(),
            array(
                "ID" => $arg2["PRODUCT_ID"],
            ),
            false,
            false,
            array("ID", "IBLOCK_ID")
        );
        if ($arPriceElement = $rsPriceElement->Fetch()) {
            $arCatalog = CCatalog::GetByID($arPriceElement["IBLOCK_ID"]);
            if (is_array($arCatalog)) {
                //Check if it is offers iblock
                if ($arCatalog["OFFERS"] == "Y") {
                    //Find product element
                    $rsElement = CIBlockElement::GetProperty(
                        $arPriceElement["IBLOCK_ID"],
                        $arPriceElement["ID"],
                        "sort",
                        "asc",
                        array("ID" => $arCatalog["SKU_PROPERTY_ID"])
                    );
                    $arElement = $rsElement->Fetch();
                    if ($arElement && $arElement["VALUE"] > 0) {
                        $ELEMENT_ID = $arElement["VALUE"];
                        $IBLOCK_ID = $arCatalog["PRODUCT_IBLOCK_ID"];
                        $OFFERS_IBLOCK_ID = $arCatalog["IBLOCK_ID"];
                        $OFFERS_PROPERTY_ID = $arCatalog["SKU_PROPERTY_ID"];
                    }
                } //or iblock wich has offers
                elseif ($arCatalog["OFFERS_IBLOCK_ID"] > 0) {
                    $ELEMENT_ID = $arPriceElement["ID"];
                    $IBLOCK_ID = $arPriceElement["IBLOCK_ID"];
                    $OFFERS_IBLOCK_ID = $arCatalog["OFFERS_IBLOCK_ID"];
                    $OFFERS_PROPERTY_ID = $arCatalog["OFFERS_PROPERTY_ID"];
                } //or it's regular catalog
                else {
                    $ELEMENT_ID = $arPriceElement["ID"];
                    $IBLOCK_ID = $arPriceElement["IBLOCK_ID"];
                    $OFFERS_IBLOCK_ID = false;
                    $OFFERS_PROPERTY_ID = false;
                }
            }
        }
    } //Check for iblock event
    elseif (is_array($arg1) && $arg1["ID"] > 0 && $arg1["IBLOCK_ID"] > 0) {
        //Check if iblock has offers
        $arOffers = CIBlockPriceTools::GetOffersIBlock($arg1["IBLOCK_ID"]);
        if (is_array($arOffers)) {
            $ELEMENT_ID = $arg1["ID"];
            $IBLOCK_ID = $arg1["IBLOCK_ID"];
            $OFFERS_IBLOCK_ID = $arOffers["OFFERS_IBLOCK_ID"];
            $OFFERS_PROPERTY_ID = $arOffers["OFFERS_PROPERTY_ID"];
        }
    }

    if ($ELEMENT_ID) {
        static $arPropCache = array();
        if (!array_key_exists($IBLOCK_ID, $arPropCache)) {
            //Check for MINIMAL_PRICE property
            $rsProperty = CIBlockProperty::GetByID("MINIMUM_PRICE", $IBLOCK_ID);
            $arProperty = $rsProperty->Fetch();
            if ($arProperty)
                $arPropCache[$IBLOCK_ID] = $arProperty["ID"];
            else
                $arPropCache[$IBLOCK_ID] = false;
        }

        if ($arPropCache[$IBLOCK_ID]) {
            //Compose elements filter
            $arProductID = array($ELEMENT_ID);
            if ($OFFERS_IBLOCK_ID) {
                $rsOffers = CIBlockElement::GetList(
                    array(),
                    array(
                        "IBLOCK_ID" => $OFFERS_IBLOCK_ID,
                        "PROPERTY_" . $OFFERS_PROPERTY_ID => $ELEMENT_ID,
                        "ACTIVE_DATE" => "Y",
                        "ACTIVE" => "Y",
                        "<CATALOG_QUANTITY" => AVALIABLE_VAL,
                        ">CATALOG_QUANTITY" => 0
                    ),
                    false,
                    false,
                    array("ID")
                );
                while ($arOffer = $rsOffers->Fetch())
                    $arProductID[] = $arOffer["ID"];
            }

            $minPrice = false;
            $maxPrice = false;
            //Get prices
            $rsPrices = CPrice::GetList(
                array(),
                array(
                    "BASE" => "Y",
                    "PRODUCT_ID" => $arProductID,
                )
            );
            while ($arPrice = $rsPrices->Fetch()) {
                $PRICE = $arPrice["PRICE"];

                if ($minPrice === false || $minPrice > $PRICE)
                    $minPrice = $PRICE;

                if ($maxPrice === false || $maxPrice < $PRICE)
                    $maxPrice = $PRICE;
            }

            //Save found minimal price into property
            if ($minPrice !== false) {
                CIBlockElement::SetPropertyValuesEx(
                    $ELEMENT_ID,
                    $IBLOCK_ID,
                    array(
                        "MINIMUM_PRICE" => $minPrice,
                        "MAXIMUM_PRICE" => $maxPrice,
                    )
                );
            }
        }
    }
}

Before mail sent

<?php

AddEventHandler('sale', 'OnOrderNewSendEmail', 'processOrderMailTemplate');

function processOrderMailTemplate($ID, &$eventName, &$arFields)
{
    if ($eventName == 'SALE_NEW_ORDER') {

    }
}

Restrict 1C from updating element fields

AddEventHandler(
   'sale',
   'OnBeforeIBlockElementUpdate',
   array('OnBeforeIBlockElementUpdate', 'restrictFieldsUpdateFrom1C')
);

class OnBeforeIBlockElementUpdate
{
    public static $group1cId = 23;

    public static function restrictFieldsUpdateFrom1C(&$arFields)
    {
        global $USER;
        if(in_array(self::$group1cId, $USER->GetUserGroupArray()))
        {
            unset($arFields["PREVIEW_TEXT"]);
            unset($arFields["DETAIL_TEXT"]);
            unset($arFields["CODE"]);
        }
    }
}

D7

This section contains scripts with example of using Bitrix D7 core

ORM

Select with Query object

<?php
use \Bitrix\Main\Loader;
use \Bitrix\Main\Entity\Query;
use \Bitrix\Crm\DealTable;

Loader::includeModule('crm');

$query = new Query(DealTable::getEntity());
$query->setFilter(array(
    'STAGE_ID' => 'WON',
));

$query->setSelect(array(
    'ID',
    'LEAD_DATE_CREATE' => 'LEAD_BY.DATE_CREATE',
    'CONTACT_DATE_CREATE' => 'CONTACT_BY.DATE_CREATE',
    'USER_ASSIGNED' => 'CONTACT_BY.ASSIGNED_BY_ID',
    'CLOSEDATE' => 'CLOSEDATE',
    'MONEY' => 'OPPORTUNITY',
    'CURRENCY' => 'CURRENCY_ID'
));

$result = $query->exec();

$deals = array();
while ($arDeal = $result->fetch()) {

}

Select with Entity object

<?php
use \Bitrix\Main\Loader;
use \Bitrix\Crm\DealTable;

Loader::includeModule('crm');

$deals = DealTable::getList([
    'filter' => [
        'ID' => $dealId
    ]
])->fetch();

Join with ORM

<?php

use \Bitrix\Main\Loader;
use \Bitrix\Main\Entity\Query;
use \Bitrix\Crm\DealTable;

Loader::includeModule('crm');

$arResult = array();
$query = new Query(LeadTable::getEntity());
$query
    //JOIN for b_crm_status table
    ->registerRuntimeField(
        'STATUSES',
        array(
            'data_type' => '\\Bitrix\\Crm\\StatusTable',
            'reference' => array(
                '=this.STATUS_ID' => 'ref.STATUS_ID',
                '=ref.ENTITY_ID' => new SqlExpression('"STATUS"')
            ),
        )
    )
    ->setSelect(array('STATUS_NAME' => 'STATUSES.NAME'))
    ->setFilter(
        array(
            'ID' => $dealId,
        )
    )
    ->setOrder(array('DATE_CREATE' => 'ASC'));

$result = $query->exec();

while ($arLead = $result->fetch()) {
    $arResult[] = $arLead;
}

Bitrix\Main\Application

<?php
use Bitrix\Main\Application;

$application = Application::getInstance();

$docRoot = Application::getDocumentRoot();
$connection = Application::getConnection();

Bitrix\Main\Context

<?php
use Bitrix\Main\Application;
use Bitrix\Main\Context;

$context = Application::getInstance()->getContext();
//$context = Context::getCurrent();

$request = $context->getRequest();
$server = $context->getServer();
$siteId = $context->getSite();
$langId = $context->getLanguage();

Bitrix\Main\Request

<?php
use Bitrix\Main\Context;
use Bitrix\Main\Request;

$context = Context::getCurrent();

$request = $context->getRequest();
//$request = Context::getCurrent()->getRequest();

$value = $request->get("param");
$value = $request["param"];
$value = $request->getQuery("param");
$values = $request->getQueryList();
$value = $request->getPost("param");
$values = $request->getPostList();
$value = $request->getFile("param");
$values = $request->getFileList();
$value = $request->getCookie("param");
$values = $request->getCookieList();

$method = $request->getRequestMethod();
$flag = $request->isGet();
$flag = $request->isPost();
$flag = $request->isAjaxRequest();
$flag = $request->isHttps();

$flag = $request->isAdminSection();
$requestUri = $request->getRequestUri();
$requestPage = $request->getRequestedPage();
$rDir  = $request->getRequestedPageDirectory();

Bitrix\Main\Server

<?php
use Bitrix\Main\Context;
use Bitrix\Main\Server;

$context = Context::getCurrent();

$server = $context->getServer();
//$server = Context::getCurrent()->getServer();

$server->getDocumentRoot();
$server->getPersonalRoot();
$server->getHttpHost();
$server->getServerName();
$server->getServerAddr();
$server->getServerPort();
$server->getRequestUri();
$server->getRequestMethod();
$server->getPhpSelf();
$server->getScriptName();
$server->get('HTTP_ACCEPT');

Basket

Bitrix\Sale\Basket

<?php
use Bitrix\Sale;

//cur user basket
$basket = Sale\Basket::loadItemsForFUser(Sale\Fuser::getId(), Bitrix\Main\Context::getCurrent()->getSite());

//order's basket
$basket = Sale\Order::load($orderId)->getBasket();

$price = $basket->getPrice();
$fullPrice = $basket->getBasePrice();
$weight = $basket->getWeight();

//add to basket
if ($item = $basket->getExistsItem('catalog', $productId)) {
    $item->setField('QUANTITY', $item->getQuantity() + $quantity);
} else {
    $item = $basket->createItem('catalog', $productId);
    $item->setFields(array(
        'QUANTITY' => $quantity,
        'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
        'LID' => \Bitrix\Main\Context::getCurrent()->getSite(),
        'PRODUCT_PROVIDER_CLASS' => 'CCatalogProductProvider',
    ));
}
$basket->save();

//delete basket item
$basket->getItemById($id)->delete();
$basket->save();

//CAN_BUY=Y items
$orderBasket = $basket->getOrderableItems();

Bitrix\Sale\BasketItem

<?php
use Bitrix\Sale;

$basketItems = $basket->getBasketItems();

foreach ($basket as $basketItem) {
    echo $basketItem->getField('NAME') . ' - ' . $basketItem->getQuantity() . '<br />';
}

$item = $basketItems[0];
$item->getId();
$item->getProductId();
$item->getPrice();
$item->getQuantity();
$item->getFinalPrice();
$item->getWeight();
$item->getField('NAME');
$item->canBuy();
$item->isDelay();

$item->getPropertyCollection();
$item->getCollection();

//operations
$item->setField('QUANTITY', $quantity);
$item->setFields(array(
    'QUANTITY' => $quantity,
    'CUSTOM_PRICE' => $customPrice,
));

$item->delete();
$item->save(); //or $basket->save();

Order

Bitrix\Sale\Order

<?php
use Bitrix\Sale;

$order = Sale\Order::load($orderId);

//fields
$order->getId();
$order->getSiteId();
$order->getDateInsert();
$order->getPersonTypeId();
$order->getUserId();

$order->getPrice();
$order->getDiscountPrice();
$order->getDeliveryPrice();
$order->getSumPaid();
$order->getCurrency();

$order->isPaid();
$order->isAllowDelivery();
$order->isShipped();
$order->isCanceled();

$allFields = $order->getAvailableFields();
$order->getField("ORDER_WEIGHT");
$order->getField('PRICE');

//change
$order->setField('USER_DESCRIPTION', 'Comment');
$order->save();

//payments and deliveries
$paymentIds = $order->getPaymentSystemId();
$deliveryIds = $order->getDeliverySystemId();

//discounts
$discountData = $order->getDiscount()->getApplyResult();

//basket
$order->setBasket($basket);
$basket = $order->getBasket();

Bitrix\Sale\PropertyValue

<?php
$propertyCollection = $order->getPropertyCollection();

$props = $propertyCollection->getArray();
$propGroups = $propertyCollection->getGroups();
$propsFromGroup = $propertyCollection->getGroupProperties($groupId);

$emailPropValue = $propertyCollection->getUserEmail();
$namePropValue = $propertyCollection->getPayerName();
$locPropValue = $propertyCollection->getDeliveryLocation();
$taxLocPropValue = $propertyCollection->getTaxLocation();
$profNamePropVal = $propertyCollection->getProfileName();
$zipPropValue = $propertyCollection->getDeliveryLocationZip();
$phonePropValue = $propertyCollection->getPhone();
$addressPropValue = $propertyCollection->getAddress();

$somePropValue = $propertyCollection->getItemByOrderPropertyId($orderPropertyId);
$somePropValue->getValue();
$somePropValue->getViewHtml();

$arProp = $somePropValue->getProperty();
$propId = $somePropValue->getPropertyId();
$propName = $somePropValue->getName();
$isRequired = $somePropValue->isRequired();
$propPerson = $somePropValue->getPersonTypeId();
$propGroup = $somePropValue->getGroupId();

//update
$somePropValue->setValue("value");
$order->save();

Files and directories operations

Bitrix\Main\IO\File

<?php
use Bitrix\Main\IO;
use Bitrix\Main\Application;

$file = new IO\File(Application::getDocumentRoot() . "/file.txt");

//file info
$isExist = $file->isExists();

$dir = $file->getDirectory();
$dir = $file->getDirectoryName();

$fileName = $file->getName();
$fileExt = $file->getExtension();
$fileSize = $file->getSize();
$contentType = $file->getContentType();

$createdAt = $file->getCreationTime();
$accessAt = $file->getLastAccessTime();
$modifiedAt = $file->getModificationTime();

$perms = $file->getPermissions();
$perms = substr(sprintf('%o', $file->getPermissions()), -3);

//file operations
$content = $file->getContents();
$file->putContents("data");
$file->putContents("data", IO\File::APPEND);
$file->readFile();

$file->rename(Application::getDocumentRoot() . "/new_file.txt");
$file->delete();

Bitrix\Main\IO\Directory

<?php
use Bitrix\Main\IO;
use Bitrix\Main\Application;

$dir = new IO\Directory(Application::getDocumentRoot() . "/test/");

$dir->create();

//dir info
$isExist = $dir->isExists();

$createdAt = $dir->getCreationTime();
$accessAt = $dir->getLastAccessTime();
$modifiedAt = $dir->getModificationTime();

$perms = $dir->getPermissions();
$perms = substr(sprintf('%o', $dir->getPermissions()), -3);

//dir operations
$childDir = $dir->createSubdirectory("child");
$dir->rename(Application::getDocumentRoot() . "/another_path/");
$dir->delete();

$files = $dir->getChildren();

Bitrix\Main\IO\Path

<?php
use Bitrix\Main\IO;
use Bitrix\Main\Application;

$path = Application::getDocumentRoot() . "/some_dir/some_file.ext";
$fileExt = IO\Path::getExtension($path);
$fileName = IO\Path::getName($path);
$fileDir = IO\Path::getDirectory($path);

HTTP

<?php
use \Bitrix\Main\Application;
use \Bitrix\Main\Web\Uri;
use \Bitrix\Main\Web\HttpClient;

//URI
$uri = new Uri("http://username:password@example.com/some/path/?param1=value#comments");

$uri->getLocator();
$uri->getUri();
$uri->getHost();
$uri->getUser();
$uri->getPass();
$uri->getPath();
$uri->getPathQuery();
$uri->getPort();
$uri->getQuery();
$uri->getScheme();
$uri->deleteParams(array("param1"));
$uri->getUri();
$uri->addParams(array("param2" => "value"));
$uri->getUri();

//HTTP Client
$options = array(
    "redirect" => true,
    "redirectMax" => 5,
    "waitResponse" => true,
    "socketTimeout" => 30,
    "streamTimeout" => 60,
    "version" => HttpClient::HTTP_1_0, // HttpClient::HTTP_1_0 or HttpClient::HTTP_1_1
    "proxyHost" => "",
    "proxyPort" => "",
    "proxyUser" => "",
    "proxyPassword" => "",
    "compress" => false, // Accept-Encoding: gzip
    "charset" => "", //request body charset
    "disableSslVerification" => false,
);
$httpClient = new HttpClient($options);

//headers
$name = "User-Agent";
$value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A";
$httpClient->setHeader($name, $value, true);

//cookies
$cookies = array(
    "name" => "value",
);
$httpClient->setCookies($cookies);

//basic auth
$httpClient->setAuthorization($user, $pass);

//send request
//methods - HttpClient::HTTP_GET, HttpClient::HTTP_POST, HttpClient::HTTP_PUT, HttpClient::HTTP_HEAD и HttpClient::HTTP_PATCH.
$httpClient->query($method, $url, $entityBody = null);

//result
$httpClient->getResult();
$httpClient->getStatus();
$httpClient->getContentType();
$httpClient->getEffectiveUrl();
$httpClient->getCookies();
$httpClient->getHeaders();
$httpClient->getError();

//download file
$httpClient->download('http://example.com/file.pdf', Application::getDocumentRoot() . '/upload/example/document.pdf');

Tasks with cron utility

This section contains recipes for using cron

Agents on cron

Example of file that runs agents and events on cron. Place it in local/php_interface folder.

<?php
$_SERVER['DOCUMENT_ROOT'] = realpath(dirname(__FILE__) . '/../..');
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];

define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_NO_ACCELERATOR_RESET', true);
define('BX_CRONTAB_SUPPORT', false);

require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
if ('N' != COption::GetOptionString('main', 'agents_use_crontab')) {
    COption::SetOptionString('main', 'agents_use_crontab', 'N');
}
if ('N' != COption::GetOptionString('main', 'check_agents')) {
    COption::SetOptionString('main', 'check_agents', 'N');
}

@set_time_limit(0);

CAgent::CheckAgents();
CEvent::CheckEvents();

if (CModule::IncludeModule('subscribe')) {
    $cPosting = new CPosting;
    $cPosting->AutoSend();
}

Useful functions

This section contains useful functions

Dump for admin

<?php
function pre($array, $exit = false, $hide = false)
{
    global $USER;
    if ($USER->IsAdmin()) {
        if ($hide) {
            echo "<!--";
        }

        echo "<pre>";
        var_dump($array);
        echo "</pre>";

        if ($hide) {
            echo "-->";
        }

        if ($exit) {
            exit();
        }
    }
}

Dump for admin limited by IP

<?php
function pre($array, $exit = false, $hide = false)
{
    if ($_SERVER["REMOTE_ADDR"] == "95.67.105.122") {
        if ($hide) {
            echo "<!--";
        }

        echo "<pre>";
        var_dump($array);
        echo "</pre>";

        if ($hide) {
            echo "-->";
        }

        if ($exit) {
            exit();
        }
    }
}

Export array with short array syntax

<?php
/**
 * Var expor array as PHP 5.4 notation
 * @param        $var
 * @param string $indent
 * @return mixed|string
 */
function var_export54($var, $indent = "")
{
    switch (gettype($var)) {
        case "string":
            return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"';
        case "array":
            $indexed = array_keys($var) === range(0, count($var) - 1);
            $r = [];
            foreach ($var as $key => $value) {
                $r[] = "$indent    "
                    . ($indexed ? "" : var_export54($key) . " => ")
                    . var_export54($value, "$indent    ");
            }
            return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
        case "boolean":
            return $var ? "TRUE" : "FALSE";
        default:
            return var_export($var, TRUE);
    }
}

Example of using PDO

This section contains scripts with PDO examples

<?php

set_time_limit(0);
ini_set('display_errors', 1);

$time_start = microtime(true);

$username = 'username';
$password = 'password';
$dsn = 'mysql:dbname=db_name;host=localhost';

try {
    $conn = new PDO($dsn, $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    //prepare example
    $insert = $conn->prepare("INSERT INTO table (col1, col2) VALUES (:col1, :col1)");
    $insert->bindParam(':col1', 'foo');
    $insert->bindParam(':col2', 'bar');
    $insert->execute();

    //last insert ID
    $conn->lastInsertId();

    //select query
    $select = $conn->query('SELECT * FROM table_1');
    $select->execute();
    $select->setFetchMode(PDO::FETCH_ASSOC);
    $result = $select->fetchAll();

} catch (PDOException $e) {

} catch (Exception $e) {

}

$conn = null;

Other

This section contains various recipes thant not fit to other categories

Dates on russian

<?php
setlocale(LC_ALL, 'ru_RU.UTF-8');
strftime('%d %B %Y', strtotime("+1 day"))

Phinx config

<?php
define("NOT_CHECK_PERMISSIONS", true);
define("NO_AGENT_CHECK", true);
$GLOBALS["DBType"] = 'mysql';
$_SERVER["DOCUMENT_ROOT"] = realpath(__DIR__ . '/..');
include($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// manual saving of DB resource
global $DB;
$app = \Bitrix\Main\Application::getInstance();
$con = $app->getConnection();
$DB->db_Conn = $con->getResource();
// "authorizing" as admin
$_SESSION["SESS_AUTH"]["USER_ID"] = 1;


$config = include realpath(__DIR__ . '/../bitrix/.settings.php');

return array(
    "paths" => array(
        "migrations" => realpath(__DIR__ . '/migrations/')
    ),
    "environments" => array(
        "default_migration_table" => "phinxlog",
        "default_database" => "dev",
        "dev" => array(
            "adapter" => "mysql",
            "host" => $config['connections']['value']['default']['host'],
            "name" => $config['connections']['value']['default']['database'],
            "user" => $config['connections']['value']['default']['login'],
            "pass" => $config['connections']['value']['default']['password']
        )
    )
);

Errors in bitrix core

Get last bitrix error

<?php
$error = $APPLICATION->GetException();
echo $error->GetString();

Examples of DateTime class

<?php
$curTime = time();
//get current day of week
$curDayOfWeek = date("l", $curTime);

//date calculations
$intervalStartDate = date("Y-m-d", strtotime('+2 days'));
$end = new DateTime();
$end = $end->modify('+6 weeks');

//date intervals
$begin = new DateTime($intervalStartDate);

//set interval for 1 day in step
$interval = new DateInterval('P1D');
$dateRange = new DatePeriod($begin, $interval, $end);

//loop on days intervals
foreach($dateRange as $date)
{
    $dayTimestamp = $date->getTimestamp();

    //formatting
    $printDate = $date->format("j.n.Y");
    $dayOfWeek = $date->format('l');
}

Logging examples

Using file_put_contents

<?php
$logFile = $_SERVER['DOCUMENT_ROOT'].'/local/logs/log-'.strftime("%Y-%m-%d").'.log';

$line = strftime("%d.%m.%Y | %H:%M:%S")." | LOG MESSAGE\n";
file_put_contents($logFile, $line, FILE_APPEND);

Using Monolog

$ composer require monolog/monolog
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;

$stream = new StreamHandler('logs/solutions.log');
$formatter = new LineFormatter("[%datetime%] %message%\n");
$stream->setFormatter($formatter);

$log = new Logger('logger_name');
$log->pushHandler($stream);

$log->addDebug('LOG MESSAGE');

Update 1C exchange module error

COption::SetOptionString("catalog", "DEFAULT_SKIP_SOURCE_CHECK", "Y");
COption::SetOptionString("sale", "secure_1c_exchange", "N");

Reset module files

Head to /bitrix/admin/update_system.php?lang=ru&BX_SUPPORT_MODE=Y page and find ‘System area’ block

Indices and tables