SSHFS — Альтернатива использованию SFTP/SSH клиентов

Больинство из нас работает с файлами сайта удалённо, через ftp или sftp/ssh. FTP жутко тормозной, в связи с чем я уже давно перешёл полностью на ssh (чего и вам советую).

Каким образом легко получить доступ к файлам, не используя sftp/ssh-клиент?

Есть такая чудо-штука, называемая fuse. На её основе можно делать файловые системы, которые находятся удалённо (например, smbfs). Так вот, существует sshfs, который позволяет примонтировать удалённый хост на локальный компьютер и работать с файлами так, будто они на вашем жёстком диске!

Debian-way howto:
  1. sudo apt-get install sshfs
  2. sudo mkdir /media/host-name
  3. sudo chown your-username /media/host-name
  4. sudo adduser your-username fuse
  5. sudo adduser your-username nogroup
  6. sudo gnome-session-save --logout
  7.  
  8. #after logout-login you can mount a host like this
  9. sshfs -o workaround=rename host-name.com:/working-dir/ /media/host-name
  10.  
  11. #and unmount a host like this
  12. fusermount -u /media/host-name

Как ещё упростить жизнь? :)

Я пользуюсь Убунтой, а в ней по умолчанию gedit. В настройках можно включить auto save, save backups, line numbers, auto indentation, right margin и плагин side pane, а также подсветку синтаксиса. Side pane позволяет по нажатию F9 открывать "проводник", в котором легко перейти в монтированную директорию и заняться работой.

Пишем расширение для Google Chrome - History spy

Отмазка Вступление

Иногда очень хочется "подглядеть" за кем-то, просмотрев историю посещения страниц. Но, это не всегда удаётся, ведь историю посещений можно очистить. Да и не только это - в Хроме есть "режим инкогнито", при работе в нём вообще не пишется история.

Исправим ситуацию

Решение:
  1. Написать расширение, которое будет мониторить табы, записывая всяческую информацию о посещениях
  2. Заставить расширение работать также и в incognito mode
  3. Не спалиться :)

Что ж, приступим..
  1. В любом месте создаём папку, именуем как угодно
  2. Создаём manifest.json в ней. Формат - JSON. Манифест - паспорт расширения.
    Листинг:
    1. {
    2. "name": "Mr. Trololo", //имя расширения
    3. "version": "0.1", //версия
    4. "description": "History spy.", //описание
    5. "icons": { //иконки - не обязательно
    6. "48": "48.png",
    7. "128": "128.png"
    8. },
    9.  
    10. "background_page": "main.html", //воркер
    11. "options_page": "main.html", //настройки расширения
    12. "permissions": [ //разрешения
    13. "tabs", //доступ к tabs api
    14. "unlimited_storage" //безлимит места под хранение данных
    15. ]
    16. }
    Почитать: спецификация по манифестам
  3. Теперь займёмся нашим воркером.. Он-то и будет делать всю "грязную" работу :)
    Что требуется от воркера:
    • Повесить event listener на событие onUpdated табов
    • Обрабатывать каждый вызов события, записывая информацию о посещениях в localStorage
    • При вызове настроек расширения (у нас воркер отвечает и за это, для простоты) предоставить интерфейс для просмотра истории посещений, а также её очистки.

    Для начала реализуем javascript ядро воркера, которое будет подключаться из main.html
    Листинг main.js:
    1. /*
    2.   @collection
    3.   Sorry for my bad Javascript ^_^
    4. */
    5. m = {
    6. key: 'history', //key for local storage
    7. ls: window.localStorage, //local alias
    8.  
    9. /* Clear stored data */
    10. clearData: function() {
    11. m.ls.removeItem( m.key );
    12. m.ls.setItem( m.key, "[]" ); //initialize our var' as JSON's array
    13. },
    14.  
    15. /* Get stored data helper */
    16. get: function() {
    17. if ( m.ls.getItem( m.key ) == null ) { //var' isn't initialized
    18. m.ls.setItem( m.key, "[]" );
    19. }
    20.  
    21. /* Local storage provides only string saving. Using JSON for [un]serializing arrays */
    22. return JSON.parse( m.ls.getItem( m.key ) );
    23. },
    24.  
    25. /* Set stored data helper */
    26. set: function( v ) {
    27. m.ls.setItem(
    28. m.key,
    29. JSON.stringify( (m.get()).concat( [v] ) ) //concat prev' and present data, JSON it
    30. );
    31. },
    32.  
    33. /* Callback for event listener */
    34. callbackTabs: function( id, i, tab ) {
    35. if ( tab.status == 'complete' ) { //event fires 2 times: "loading" and "complete" states
    36. m.set( { //store that
    37. date: m.date(),
    38. favIcon: tab.favIconUrl || '',
    39. url: tab.url || '',
    40. title: tab.title || '',
    41. incognito: tab.incognito
    42. } );
    43. }
    44. },
    45.  
    46. /* Ugly date format helper */
    47. date: function() {
    48. d = new Date();
    49. return '' + (
    50. ( d.getDate() > 9 ? d.getDate() : '0' + d.getDate() ) + ' ' +
    51. ['January','February','March','April','May','June','July','August',
    52. 'September','October','November','December'][d.getMonth()] +
    53. ' ' + d.getFullYear() + ', ' +
    54. ( d.getHours() > 9 ? d.getHours() : '0' + d.getHours() ) + ':' +
    55. ( d.getMinutes() > 9 ? d.getMinutes() : '0' + d.getMinutes() ) + ':' +
    56. ( d.getSeconds() > 9 ? d.getSeconds() : '0' + d.getSeconds() )
    57. );
    58. },
    59.  
    60. /* $(id) getter */
    61. $: function( id ) {
    62. return document.getElementById( id );
    63. },
    64.  
    65. /* Helper for decomposition of an URL */
    66. parseURL: function( url ) {
    67. var a = document.createElement('a');
    68. a.href = url;
    69.  
    70. //some extra parts are commented, we don't need 'em
    71. return {
    72. /* source: url,
    73. protocol: a.protocol.replace(':',''), */
    74. host: a.hostname,
    75. /* port: a.port,
    76. query: a.search,
    77. params: (function(){
    78. var ret = {},
    79. seg = a.search.replace(/^?/,'').split('&'),
    80. len = seg.length, i = 0, s;
    81. for (;i<len;i++) {
    82. if (!seg[i]) { continue; }
    83. s = seg[i].split('=');
    84. ret[s[0]] = s[1];
    85. }
    86. return ret;
    87. })(),
    88. file: (a.pathname.match(//([^/?#]+)$/i) || [,''])[1],
    89. hash: a.hash.replace('#',''), */
    90. path: a.pathname.replace(/^([^/])/,'/$1')/* ,
    91. relative: (a.href.match(/tp://[^/]+(.+)/) || [,''])[1],
    92. segments: a.pathname.replace(/^//,'').split('/') */
    93. };
    94. },
    95.  
    96. /* Displaying history helper. History iterator */
    97. displayData: function() {
    98. var html = ''; //dirty working with DOM
    99.  
    100. (m.get()).forEach( function( v ) {
    101. p = m.parseURL( v.url );
    102.  
    103. html += '<li><span>' + v.date + '</span> ' + ( v.incognito ? '<strong>incognito mode</strong> ' : '')
    104. + '<a href="' + v.url + '"><img src="'
    105. + ( v.favIcon ? v.favIcon : ('http://www.google.com/s2/favicons?domain=' + p.host) ) + '"/>'
    106. + ( v.title ? v.title : ((p.host + p.path ).substr( 0, 80 )) ) + '</a></li>';
    107. });
    108.  
    109. m.$( 'putHere' ).innerHTML = html;
    110.  
    111. return false;
    112. }
    113. };
    114.  
    115. /* Add a tabs listener */
    116. chrome.tabs.onUpdated.addListener( m.callbackTabs );
    Код отлично комментирован, как мне кажется
  4. Теперь сам воркер, обычная html страница с подключением скрипта + небольшой интерфейс.
    Код:
    1. <script type="text/javascript" src="main.js"></script>
    2. <style type="text/css">
    3. #putHere {
    4. list-style-type: none;
    5. }
    6. span {
    7. color: #ddd;
    8. -webkit-transition: 1s;
    9. }
    10. span:hover {
    11. color: #000;
    12. }
    13.  
    14. #putHere a, strong {
    15. margin-left: 20px;
    16. text-decoration: none;
    17. }
    18.  
    19. img {
    20. margin-right: 7px;
    21. position: relative;
    22. top: 3px;
    23. }
    24. </style>
    25. <ul>
    26. <li><a href="javascript:m.displayData()">Show</a></li>
    27. <li><a href="javascript:( m.clearData() || m.displayData() )">Clear</a></li>
    28. </ul>
    29. <ul id="putHere"></ul>
  5. Расширение, в принципе, готово :) Добавим в Хром..
    1. Ctrl+T, chrome://extensions/
    2. Включить режим разработчика
    3. "Загрузить распакованное расширение..", выбираем папку, которую создавали в самом начале
    4. Если всё прошло без ошибок, то ставим галочку "разрешить работать в автономном режиме" и радуемся. Если нет - действуйте по обстановке, Хром скажет в чём и где ошибка расширения.
Ну а теперь самое время проверить, работает ли действительно :) Походите по страницам, запустите режим инкогнито - тоже "посёрфите" немного.. Надоело? Тогда идём на страницу с расширениями, и открываем настройки нашего свеженаписанного :) Ссылка "Show" может заставить кого-то покраснеть однажды..

P.S. Страница расширения на Google Chrome Extensions

UPD: Перевод текста с помощью Google Translate на php

Думаю многим уже известно, что с помощью Google Translate можно делать незатейливые рерайты текста. Нужно просто перевести текст в другой язык (например, английский), затем перевести в изначальный. Сколько не пробовал - получается уникальный текст :). Правда читабельность иногда чрезвычайно ухудшается..

Предлагаю вашему вниманию скрипт хелпера для перевода текста с помощью Google Переводчика:

  1. <?php
  2. /**
  3. * @package Google Translate Helper
  4. * @author B1rdEX http://stuff-coding.blogspot.com/
  5. */
  6. // языковая пара из_какого_языка|в_какой переводить, список на translte.google.com
  7. $langpair = 'ru|en';
  8. // текст для перевода. Максимальная длина = 5120 (проверял на момент написания поста)
  9. $text = 'Важная законодательная инициатива президента: Россия может использовать свои Вооруженные силы за рубежом для отражения нападения, предотвращения агрессии против другого государства, защиты своих граждан и борьбы с пиратством. Президентский законопроект уже внесен в Госдуму.';
  10. function translate( $text, $langpair ) {
  11. $postdata = http_build_query (
  12. array (
  13. 'v' => '1.0',
  14. // обрезаем строку и переводим в Юникод
  15. 'q' => iconv ( 'windows-1251', 'utf-8', substr( strip_tags( $text ), 0, 5120 ) ),
  16. 'langpair' => $langpair,
  17. )
  18. );
  19. $options = array (
  20. 'http' => array (
  21. 'method' => 'POST',
  22. 'header' => 'Content-type: application/x-www-form-urlencoded',
  23. 'referrer' => 'http://google.com',
  24. 'content' => $postdata
  25. )
  26. );
  27. $context = stream_context_create ( $options );
  28. // Google возвращает результат в JSON
  29. $result = json_decode( file_get_contents ( 'http://ajax.googleapis.com/ajax/services/language/translate', false, $context ), 1 );
  30. return $result['responseStatus'] == 200
  31. ? iconv( 'utf-8', 'windows-1251', $result['responseData']['translatedText'] )
  32. : 'Error!' . "n" . 'Code: ' . $result['responseStatus'] . "n" . 'Details: ' . $result['responseDetails'];
  33. }
  34. echo translate( $text, $langpair );

Гостевая книга на Битриксе на стандартных компонентах

Велосипеды, какими бы они небыли, нуждаются в доработке.

Руководствуясь приведённой выше мыслью я решил сделать гостевую книгу на стандартных компонентах и API.

Необходимо: модуль "Формы", копипаст моего кода, доработка моего кода :)
Пример гостевой: http://nwcinema.ru/guest/

На странице гостевой будет располагаться форма добавления реплики (вопроса, жалобы и т.п.), а также лента вопросов-ответов с постраничной навигацией.

Форма добавления будет стандартной, лента - через API.

  1. Создаём форму:
    1. Сервис -> Веб-формы -> Настройка форм -> Создать
    2. Имя, описание и т.п. - на ваш вкус
    3. Шаблон я использовал свой (необходимо было реализовать возможность "неотображения" вопроса в ленте).
      Вот код:
      1. <?=$FORM->ShowFormDescription("")?> <?=$FORM->ShowFormNote()?><?=$FORM->ShowFormErrors()?>
      2. <br />
      3.  
      4. <table style="padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; border-collapse: collapse; " border="0" cellspacing="0" cellpadding="0" width="100%">
      5. <tbody>
      6. <tr> <td style="padding-bottom: 15px; padding-right: 20px; " valign="top" width="15%" align="right"><?=$FORM->ShowInputCaption("NAME","")?></td> <td><?=$FORM->ShowInput('NAME')?> </td> </tr>
      7.  
      8. <tr> <td style="padding-bottom: 15px; padding-right: 20px; " valign="top" align="right"><?=$FORM->ShowInputCaption("CITY","")?></td> <td><?=$FORM->ShowInput('CITY')?></td> </tr>
      9.  
      10. <tr> <td style="padding-bottom: 15px; padding-right: 20px; " valign="top" align="right"><?=$FORM->ShowInputCaption("EMAIL","")?></td> <td><?=$FORM->ShowInput('EMAIL')?></td> </tr>
      11.  
      12. <tr> <td style="padding-bottom: 15px; padding-right: 20px; " valign="top" align="right"><?=$FORM->ShowInputCaption("MESS","")?></td> <td><?=$FORM->ShowInput('MESS')?> </td> </tr>
      13.  
      14. <tr><td style="padding-bottom: 15px; padding-right: 20px; " valign="top" align="right"><?=$FORM->ShowInput('PRIVATE')?></td><td valign="top"><?=$FORM->ShowInputCaption("PRIVATE","")?> </td></tr>
      15.  
      16. <tr><td style="padding-bottom: 15px; padding-right: 20px; " valign="top" align="right">Введите текст на картинке<?=$FORM->ShowRequired()?></td><td valign="top"><?=$FORM->ShowCaptchaImage()?>
      17. <br />
      18. <?=$FORM->ShowCaptchaField()?></td></tr>
      19. </tbody>
      20. </table>
      21.  
      22. <br />
      23. <?=$FORM->ShowSubmitButton("","")?>
  2. Добавляем вопросы на форму:

    Сообщение - textarea, "Я не хочу..." - checkbox, остальные - text

  3. Добавляем статус формы
  4. Создаём страничку с гостевой (в моём случае - /guest/index.php), вот код:
    1. <?
    2. require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
    3. $APPLICATION->SetTitle("Жалобная книга");
    4. ?>
    5. <p>
    6. <?php /* Вставляем нашу формочку через компонент, не забываем поправить "WEB_FORM_ID", поставив свой ID формы */ ?>
    7. <?$APPLICATION->IncludeComponent("bitrix:form.result.new", "comments", Array(
    8. "WEB_FORM_ID" => "1",
    9. "IGNORE_CUSTOM_TEMPLATE" => "N",
    10. "USE_EXTENDED_ERRORS" => "N",
    11. "SEF_MODE" => "N",
    12. "SEF_FOLDER" => "/guest/",
    13. "CACHE_TYPE" => "N",
    14. "CACHE_TIME" => "3600",
    15. "LIST_URL" => "",
    16. "EDIT_URL" => "",
    17. "SUCCESS_URL" => "",
    18. "CHAIN_ITEM_TEXT" => "",
    19. "CHAIN_ITEM_LINK" => "",
    20. "VARIABLE_ALIASES" => array(
    21. "WEB_FORM_ID" => "WEB_FORM_ID",
    22. "RESULT_ID" => "RESULT_ID",
    23. )
    24. )
    25. );?></p>
    26.  
    27. <?php
    28. $f = array( );
    29.  
    30. if ( CModule::IncludeModule("form") ) {
    31.  
    32. /* Получаем ленту сообщений, единичка - ID нашей формы */
    33. CForm::GetResultAnswerArray(
    34. 1,
    35. $f,
    36. $f,
    37. $answers,
    38. array(
    39.  
    40. )
    41. );
    42.  
    43. if ( count( $answers ) ) {
    44. $rez = array( );
    45. foreach ( $answers as $id => $f ) {
    46. $x = CFormResult::GetByID( $id );
    47. if ( $x && ($x = $x->GetNext()) && ($d = date_parse( $x['DATE_CREATE'] )) ) {
    48.  
    49. $x = array( 'DATE_CREATE' => date(
    50. 'd.m.Y H:i:s',
    51. (mktime(
    52. $d['hour'],
    53. $d['minute'],
    54. $d['second'],
    55. $d['month'],
    56. $d['day'],
    57. $d['year']
    58. ) + 7*60*60)
    59. ) );
    60.  
    61. foreach ( $f as $s => $v ) {
    62. $v = $v[0];
    63.  
    64. $x[ $s ] = ( $v['VARNAME'] == 'PRIVATE' ? $v['VALUE'] : $v["USER_TEXT"] );
    65. }
    66.  
    67. if ( ! $x['PRIVATE'] )
    68. $rez[ $id ] = $x;
    69. }
    70. }
    71.  
    72. /* Сортировать будем DESC по ID */
    73. krsort( $rez );
    74.  
    75. $p = $_GET['p'] > 0 ? $_GET['p'] : 1;
    76. $onP = 10; // количество вопросов в ленте на странице
    77. $elz = count ( $rez );
    78.  
    79. if ( $elz > $onP ) {
    80. $rez = array_slice( $rez, ( $p > 1 ? ($p * $onP - $onP) : 0 ), $onP, 1 );
    81. }
    82.  
    83. /* Выводим ленту */
    84. echo '<h2>Лента сообщений</h2>';
    85. foreach ( $rez as $v ) {
    86. echo '<p><b>'.$v["NAME"].'</b>'
    87. . ( $v['CITY'] ? ' (' . $v["CITY"] . ')' : '' ) . '<br />';
    88. echo '<span style="color:#aaa">'.$v["DATE_CREATE"].'</span><br />';
    89. echo
    90. str_replace(
    91. array(
    92. '<r>',
    93. '</r>'
    94. ),
    95. array(
    96. '<p class="reply">',
    97. '</p>'
    98. ),
    99. $v["MESS"]
    100. )
    101. . '<div class="line_1" style="margin: 5px 0px 0px 0px; padding: 1px;"></div></p>';
    102. }
    103.  
    104. /* Выводим постраничную навигацию */
    105. if ( $elz > $onP ) {
    106. $pages = ceil( $elz / $onP );
    107. $rez = array();
    108. foreach ( range( 1, $pages ) as $v ) {
    109. $rez[] = $p == $v
    110. ? "<b>$v</b>"
    111. : "<a href='?p=$v'>$v</a>";
    112. }
    113. echo '<p><font class="text"> ' . ($p * $onP - $onP + 1) . ' - ' . ( $p * $onP > $elz ? $elz : $p * $onP ) . ' из ' . $elz . '<br></font>
    114. <font class="text">
    115. Страницы: ' . join( ' ', $rez ) . '
    116. </font></p>';
    117. }
    118. }
    119.  
    120. }
    121. ?>
    122. <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");?>
    В коде есть комментарии, не забудьте отредактировать под себя.

  5. Ключевой момент - ответы на вопросы
    1. Заходим в результаты формы
    2. Заходим в редактирование вопроса, на который нужно дать ответ. В тегах <r><r> Вводим ответ

  6. Добавляем css-правило и радуемся жизни :)
    1. p.reply {
    2. color: #C2097F;
    3. /* font-family: arial;
    4. font-size: 0.8em; */
    5. margin:10px 0 10px 30px;
    6. }

Часы, да чтобы тикали :)

Иногда необходимо вывести дату и время яваскриптом, например так:

Задача тривиальная, но, всё же, вот код:
  1. <script language="JavaScript"><!--
  2. document.write ((function(d){
  3. return(
  4. ( d.getDate() > 9 ? d.getDate() : '0' + d.getDate() ) + ' ' +
  5. ['Января','Февраля','Марта','Апреля','Мая','Июня','Июля','Августа','Сентября','Октября','Ноября','Декабря'][d.getMonth()] +
  6. ' ' + d.getFullYear() + ' г. ' +
  7. ( d.getHours() > 9 ? d.getHours() : '0' + d.getHours() ) + ':' + ( d.getMinutes() > 9 ? d.getMinutes() : '0' + d.getMinutes() )
  8. );
  9. })(new Date()));
  10. --></script>

Чтобы тикали:
  1. <div id="beautyTimeThisTag">here will be datetime</div>
  2. <script language="JavaScript"><!--
  3. setInterval( function() {
  4. document.getElementById( 'beautyTimeThisTag' ).innerHTML = ((function(d){
  5. return(
  6. ( d.getDate() > 9 ? d.getDate() : '0' + d.getDate() ) + ' ' +
  7. ['Января','Февраля','Марта','Апреля','Мая','Июня','Июля','Августа','Сентября','Октября','Ноября','Декабря'][d.getMonth()] +
  8. ' ' + d.getFullYear() + ' г. ' +
  9. ( d.getHours() > 9 ? d.getHours() : '0' + d.getHours() ) + ':' + ( d.getMinutes() > 9 ? d.getMinutes() : '0' + d.getMinutes() )
  10. );
  11. })(new Date()));
  12. }, 1000 );
  13. --></script>

Ресайз картинок на лету (для Битрикса и не только)

Битрикс - хорошая (отличной не назовёшь) система управления сайтами. И всё в ней хорошо, даже API есть, если не хватает компонентов (а мне, последнее время, попадаются как-раз специфические задачи, которые компонентами не решить).

Так вот, неоднократно мне понадобилось обжимать картинки на Битрикс-сайтах.
Встроенный CFile::ShowImage() всего-навсего задаёт width и height у картинок, что, в большинстве случаев, неприемлемо. Так и был придуман этот незаурядный способ ресайза картинок на лету.

Итак, по порядку:
  1. Создаём папку resized в корневой директории сайта (mkdir resized)
  2. Создаём resize.php в корне, со следующим содержимым:
    1. <?php
    2. if ( $_GET['f'] && ($_GET['x'] && $_GET['x'] <= 1440) ) {
    3. createThumb( '.' . base64_decode( $_GET['f'] ), ('./resized/' . $_GET['f'] . '>' .$_GET['x']), $_GET['x'] );
    4. }
    5. function createThumb($resource, $dest, $x_scale) {
    6. $check = GetImageSize ( $resource );
    7. $y_scale = floor ( $x_scale / ( $check [0] / $check [1] ) );
    8. $im_dest = imagecreatetruecolor ( $x_scale, $y_scale );
    9. if ($check [2] == IMAGETYPE_JPEG) {
    10. $im_src = ImageCreateFromJPEG ( $resource );
    11. } elseif ($check [2] == IMAGETYPE_GIF) {
    12. $im_src = ImageCreateFromGIF ( $resource );
    13. } elseif ($check [2] == IMAGETYPE_PNG) {
    14. $im_src = imagecreatefrompng ( $resource );
    15. }
    16. if ($im_src && ImageCopyResampled ( $im_dest, $im_src, 0, 0, 0, 0, $x_scale, $y_scale, $check [0], $check [1] )) {
    17. if ($check [2] == IMAGETYPE_JPEG) {
    18. header('Content-type: image/jpeg');
    19. return ImageJPEG ( $im_dest, $dest, 99 ) && ImageJPEG ( $im_dest, null, 99 );
    20. } elseif ($check [2] == IMAGETYPE_GIF) {
    21. header('Content-type: image/gif');
    22. return ImageGIF ( $im_dest, $dest, 99 ) && ImageGIF ( $im_dest, null, 99 );
    23. } elseif ($check [2] == IMAGETYPE_PNG) {
    24. header('Content-type: image/png');
    25. return imagepng ( $im_dest, $dest, 99 ) && imagepng ( $im_dest, null, 99 );
    26. }
    27. }
    28. return 0;
    29. }
    30. ?>
  3. Редактируем .htaccess (или создаём, если его нет):
    1. <IfModule mod_rewrite.c>
    2. RewriteEngine On
    3. RewriteCond %{REQUEST_FILENAME} !-f
    4. RewriteRule ^resized/([a-zA-Z0-9=]+)>([0-9]{1,3})$ /resize.php?f=$1&x=$2 [QSA,L]
    5. </IfModule>
  4. Добавляем хелпер в /bitrix/header.php (или другой файл, который инклудится везде):
    1. <?php
    2. // Bitrix line
    3. require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog.php");
    4. // Our helper
    5. function resizeHelper( $path, $x, $addi = '' ) {
    6. $path = '/resized/'
    7. . base64_encode(
    8. ((string)(float)$path === (string)$path)
    9. ? CFile::GetPath( $path )
    10. : $path
    11. )
    12. . '>' . $x;
    13. return '<img src="' . $path .'" width="' . $x . '"' . $addi . '/>';
    14. }
    15. ?>
  5. Вот и всё :)

Параметры resizeHelper():
  1. $path - путь к картинке или её Битрикс ID (что обычно и возвращается из инфоблока);
  2. $x - необходимая ширина картинки (высота вычисляется автоматически, пропорционально ширине);
  3. $addi - дополнительные параметры тега <img/>, которые будут просто вставлены (например, style="border:1px solid #666;padding:2px;margin-right:15px").

В папке /resized сохраняются картинки с новыми размерами (для каждого размера картинки - отдельный файл) - при повторном запросе, будет возвращена уже уменьшенная картинка (для этого-то мы и редактировали .htaccess).

Пример использования:
  1. <?php
  2. CModule::IncludeModule("iblock");
  3. // Bitrix API GetList()
  4. $x = CIBlockElement::GetList(
  5. array(
  6. 'RAND' => 'ASC',
  7. ),
  8. array(
  9. 'IBLOCK_ID'=> 8,
  10. '>=DATE_ACTIVE_TO' => ConvertTimeStamp(
  11. mktime(
  12. 0, 0, 0,
  13. date( 'n' ),
  14. date( 'j' )
  15. ),
  16. 'FULL'
  17. ),
  18. '!PROPERTY_IMAGE_LEFT_VALUE' => 'false',
  19. //'ID' => 69
  20. ),
  21. false,
  22. array(
  23. //'nTopCount' => 1
  24. ),
  25. array(
  26. 'IBLOCK_ID',
  27. 'PROPERTY_image_left',
  28. 'NAME',
  29. 'PREVIEW_TEXT',
  30. 'DETAIL_PAGE_URL',
  31. 'PREVIEW_PICTURE'
  32. )
  33. );
  34. // Iterate over it
  35. while ( $x && ($s = $x->GetNext()) ) {
  36. if ( ($i = $s['PROPERTY_IMAGE_LEFT_VALUE']) or ($i = $s['PREVIEW_PICTURE']) ) {
  37. // Below is out helper: put image $i (int or str), 330px wide, with border-styling (style="")
  38. ?>
  39. <div><a href="<?=$s['DETAIL_PAGE_URL']?>"><?=resizeHelper($i, 330, 'style="border: 5px solid #fff;"')?></a></div>
  40. <div class="info">
  41. <h2><?=$s['NAME']?></h2>
  42. <p>
  43. <?=$s['PREVIEW_TEXT']?> <br><br>
  44. <a class="more_1" href="<?=$s['DETAIL_PAGE_URL']?>">подробнее</a>
  45. </p>
  46. </div>
  47. <?
  48. break;
  49. } else {
  50. continue;
  51. }
  52. }
  53. ?>