Скрипт обновления цен в Presta Shop [обновляет цену, скидку, количество]

Как-то давно нашёл в просторах скрипт для PrestaShop, который обновлял количество и цену у товара. Знакомому нужен же был более полный функционал.
С количеством и ценой проблем не возникает, а вот со скидкой пришлось повозиться. Скидка хранится в таблице ps_specific_price (ps — префикс таблицы, у вас он может быть другим).
Сам код:

<?php

define('PS_ADMIN_DIR', getcwd());
include(PS_ADMIN_DIR . '/../config/config.inc.php');
include(PS_ADMIN_DIR . '/functions.php');
include(PS_ADMIN_DIR . '/header.inc.php');
echo '<div style="text-align:left;">';

// Проверяем загружен ли файл
if (is_uploaded_file($_FILES["filename"]["tmp_name"]))
{
    // Если файл загружен успешно, перемещаем его из временной директории в конечную
    move_uploaded_file($_FILES["filename"]["tmp_name"], "" . $_SERVER["DOCUMENT_ROOT"] . "/upload/" . $_FILES["filename"]["name"]);
    $file_path = "" . $_SERVER["DOCUMENT_ROOT"] . "/upload/" . $_FILES["filename"]["name"] . "";

// Меняем кодировку файла с windows-1251 на utf-8
    $file = file_get_contents("" . $file_path . "");
    $file = iconv("windows-1251", "utf-8", $file);
    file_put_contents("" . $file_path . "", $file);

//меняем локаль на хостинге
    if (!setlocale(LC_ALL, 'ru_RU.utf8'))
        setlocale(LC_ALL, 'en_US.utf8'); if (setlocale(LC_ALL, 0) == 'C')
        die('Не поддерживается ни одна из перечисленных локалей (ru_RU.utf8, en_US.utf8)');
    if (($handle_f = fopen($file_path, "r")) !== FALSE)
    {
        //начинаем цикл чтения csv
        while (($data_f = fgetcsv($handle_f, 99999, ";")) !== FALSE)
        {

            //ищем товар по supplier_reference
            $sql = "SELECT id_product FROM ps_product WHERE supplier_reference = '" . $data_f[0] . "'";
            $id_product = Db::getInstance()->getValue($sql, 0);

            //если такой товар есть, обновляем количество и цену
            if ($id_product)
            {
                if ((isset($data_f[1])))
                    $sql = mysql_query("UPDATE `ps_product` SET `quantity` ='" . $data_f[1] . "'  WHERE `id_product`='" . $id_product . "' LIMIT 1");

                if ((isset($data_f[2])))
                    $sql = mysql_query("UPDATE `ps_product` SET`price` = '" . $data_f[2] . "' WHERE `id_product`='" . $id_product . "' LIMIT 1");
                if ((isset($data_f[4])))
                    $sql = mysql_query("UPDATE `ps_product` SET `on_sale` = '" . $data_f[4] . "' WHERE `id_product`='" . $id_product . "' LIMIT 1");

                if ((isset($data_f[3])))
                    $sql = mysql_query("UPDATE `ps_product` SET `wholesale_price` ='" . $data_f[3] . "' WHERE `id_product`='" . $id_product . "' LIMIT 1");
                if ((isset($data_f[5])))
                {
                    if ($data_f[5] == 0)
                    {
                        $sql = mysql_query("DELETE FROM `ps_specific_price` WHERE `id_product`='" . $id_product . "' LIMIT 1");
                    }
                    else
                    {
                        $sql = mysql_query("DELETE FROM `ps_specific_price` WHERE `id_product`='" . $id_product . "' LIMIT 1");
                        $s = str_replace(',', '.', $data_f[5] / 100);
                        $sql = mysql_query(
                                "INSERT INTO `uds4lif_vne`.`ps_specific_price` (
`id_specific_price` ,
`id_product` ,
`id_shop` ,
`id_currency` ,
`id_country` ,
`id_group` ,
`price` ,
`from_quantity` ,
`reduction` ,
`reduction_type` ,
`from` ,
`to`
)
VALUES (
NULL , '" . $id_product . "', '1', '0', '0', '0', '0', '1', '" . $s . "', 'percentage', '0000-00-00 00:00:00', '0000-00-00 00:00:00'
);
"
                        );
                    }
                }

                echo "<p style='color:green'>товар с штрихкодом <b>" . $data_f[0] . "</b> обновлен</p>";
            }
            else
            {
                echo "<p style='color:red  '>товар с штрихкодом <b>" . $data_f[0] . "</b> не найден</p>";
            }
        }
        echo "<b>Обновление завершено</b>";
    }
    else
    {
        echo "Невозможно открыть загруженый файл";
    }
}
else
{
    echo '
<h2>Обновления цены и количества:</h2>
<form action="' . $_SERVER["PHP_SELF"] . '" method="post" enctype="multipart/form-data">
          <input type="file" name="filename"><br>
          <input type="submit" value="Загрузить"><br>
</form>
';
}

echo '</div>';
include(PS_ADMIN_DIR . '/footer.inc.php');
?>

Инструкция: Создаем/качаем ниже файл и закачиваем его в админку магазина. Путь к файлу: http://mojmagazin.ua/adminXXX/upl_price.php

Инстуркция по созданию файла CSV:

файл csv нужно заполнять так | Supplier reference #| количество | цена продажи | закупочная цена | скидка на товар: 1 – есть, 0 – нету | размер скидки в процентах|
Расчитан скрипт на то что файл в кодировке windows-1251
(в таком формате сохраняет файл эксель — «csv — разделеные точкой с запятой»)

Теперь сами файлы:

http://vazelin.org.ua/wp-content/plugins/downloads-manager/img/icons/default.gif download: update price for prestashop (1.65KB)
added: 01/03/2012
clicks: 47
description:

http://vazelin.org.ua/wp-content/plugins/downloads-manager/img/icons/default.gif download: Файл csv для импорта PrestaShop (B)
added: 01/03/2012
clicks: 53
description:

Если нужно будет для формата экселя — попросите, добавлю.
PS: Кто знает автора оригинального скрипта — маякните, чтобы добавить автора.
Спасибо: http://www.prestashop.com/forums/user/157834-surkov85/ и 4udak

Шпоргалка по кэшированию с помощью Apacha через htaccess

Один

<ifModule mod_gzip.c>
  mod_gzip_on Yes
  mod_gzip_dechunk Yes
  mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
  mod_gzip_item_include handler ^cgi-script$
  mod_gzip_item_include mime ^text/.*
  mod_gzip_item_include mime ^application/x-javascript.*
  mod_gzip_item_exclude mime ^image/.*
  mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

Два

<ifModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType text/html "access plus 1 seconds"
  ExpiresByType image/gif "access plus 2592000 seconds"
  ExpiresByType image/jpeg "access plus 2592000 seconds"
  ExpiresByType image/png "access plus 2592000 seconds"
  ExpiresByType text/css "access plus 604800 seconds"
  ExpiresByType text/javascript "access plus 216000 seconds"
  ExpiresByType application/x-javascript "access plus 216000 seconds"
</ifModule>

Три

<ifModule mod_headers.c>
  <filesMatch "\\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$">
    Header set Cache-Control "max-age=2592000, public"
  </filesMatch>
  <filesMatch "\\.(css)$">
    Header set Cache-Control "max-age=604800, public"
  </filesMatch>
  <filesMatch "\\.(js)$">
    Header set Cache-Control "max-age=216000, private"
  </filesMatch>
  <filesMatch "\\.(xml|txt)$">
    Header set Cache-Control "max-age=216000, public, must-revalidate"
  </filesMatch>
  <filesMatch "\\.(html|htm|php)$">
    Header set Cache-Control "max-age=1, private, must-revalidate"
  </filesMatch>
</ifModule>

На сегодня всё.

Когда последний раз было … PHP

Решение, которое позволяет вывести сколько прошло времени от одного события для другого.

/****
* Author: Uskov A. (Ukrainian Design Studio)
*/
                $d1 = strtotime($post_date);
                $d2 = strtotime(date("Y-m-d H:m:s"));
                $hours = round((($d2-$d1)/(60*60)));
                $minutes =floor(($d2-$d1)/60);

                if ($hours <= 1)
                {
                        if ($minutes <= 60)
                        {

                                if ($minutes < 1){$minutes = 1;}
                                $forms = array('минуту','минуты', 'минут');
                                $result = $minutes.' '.UDS_WriteRuMonth::plural_form($minutes, $forms).' назад';
                        }
                        else{
                                $result = "час назад";
                        }
                }
                else if ($hours <= 2)
                {
                        $result = "2 часа назад";
                }
                else if ($hours <= 3)
                {
                        $result = "3 часа назад";
                }
                else if (( $hours >= 3 )&& ( $hours <= 25 ))
                {
                        $result = "сегодня";
                }
                else if (( $hours >= 24 )&& ( $hours <= 48 ))
                {
                        $result = "вчера";
                }
                else
                {
                        $str_t   = strtotime ($post_date);
                        $result  = date("d ", $str_t);
                        $result .= answer(date("m", $str_t));
                        if (date("Y") != date("Y", $str_t))
                        {
                                $result .= date(" Y", $str_t);
                        }
                        $result .= date(" в H:m", $str_t);
                }

           echo $result;

Код выводит количество минут, если прошло менее 1 часа.
Если больше 3х часов, то напишет «сегодня».

Теперь дополнительные функции:
Выдает русское название месяца

function answer($month)
        {
          switch ($month){
                case 01: $result = 'января'; break;
                case 02: $result = 'февраля'; break;
                case 03: $result = 'марта'; break;
                case 04: $result = 'апреля'; break;
                case 05: $result = 'мая'; break;
                case 06: $result = 'июня'; break;
                case 07: $result = 'июля'; break;
                case 08: $result = 'августа'; break;
                case 09: $result = 'сентября'; break;
                case 10: $result = 'октября'; break;
                case 11: $result = 'ноября'; break;
                case 12: $result = 'декабря'; break;
                }
            return $result;
        }

Эта функция, которая делает правильное склонение:

function plural_form($n, $forms)
        {
               return $n%10==1&&$n%100!=11?$forms[0]:($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?$forms[1]:$forms[2]);
        }

Её использование:

$count = 22;
$forms = array('минуту','минуты', 'минут');
echo plural_fom($count, $forms);

Установка Imagick на Денвер

Краткое руководство по установке Imagick под denwer с PHP 5.2

1. Качаем от сюда Win32 dynamic at 16 bits-per-pixel.

Устанавливаем.  Во время установки выбираем, если есть такой пункт при установке, прописать PATH.
Устанавливать нужно не в ProgramFiles.

Я установил в /usr/local/ImageMagic/
z: — вирт. диск с денвером

2. В папку ext (там у нас библиотеки для php лежат) качаем и копируем php_imagick_dyn-Q8.dll
в php.ini добавляем:

extension=php_imagick_dyn-Q8.dll

Тут внимательно!!!
Нужно подобрать правильную dll библиотеку. Если эта не подходит, ищем ту, с которой будет работать. Тогда и подключать нужно ту библиотеку, которую вы скачали.

3. Добавляем переменную в настройки Апача:
Идём в \usr\local\apache\conf и в httpd.conf, в самый низ добавляем:


SetEnv MAGICK_HOME “Z:/usr/local/ImageMagick”

4. Перезапускаем денвер.

Если при старте возникают ошибки в которых содержаться *****.dll — значить не подходит библиотека для PHP. Ищите другую

Для PHP 5.3 поробуйте эту dll

Архитектура Вконтакте

автор: Иван Блинков
Самая популярная социальная сеть в рунете пролила немного света на то, как же она работает. Представители проекта в лице Павла Дурова и Олега Илларионова на конференции HighLoad++ ответили на шквал вопросов по совершенно разным аспектам работы Вконтакте, в том числе и техническим. Спешу поделиться своим взглядом на архитектуру проекта по результатам данного выступления.

Платформа

  • Debian Linux — основная операционная система
  • nginx — балансировка нагрузки
  • PHP + XCache
  • Apache + mod_php
  • memcached
  • MySQL
  • Собственная СУБД на C, созданная «лучшими умами» России
  • node.js — прослойка для реализации XMPP, живет за HAProxy
  • Изображения отдаются просто с файловой системы xfs
  • ffmpeg — конвертирование видео

Статистика

  • 95 миллионов учетных записей
  • 40 миллионов активных пользователей во всем мире (сопоставимо с аудиторией интернета в России)
  • 11 миллиардов запросов в день
  • 200 миллионов личных сообщений в день
  • Видеопоток достигает 160Гбит/с
  • Более 10 тысяч серверов, из которых только 32 — фронтенды на nginx (количество серверов с Apache неизвестно)
  • 30-40 разработчиков, 2 дизайнера, 5 системных администраторов, много людей в датацентрах
  • Каждый день ломается около 10 жестких дисков

Архитектура

Общие принципы

  • Cервера многофункциональны и используются одновременно в нескольких ролях:
    • Перебрасывание полуавтоматическое
    • Требуется перезапускать daemon’ы
  • Генерация страниц с новостями (микроблоги) происходит очень похожим образом с Facebook (см. Архитектура  Facebook), основное отличие — использование собственной СУБД вместо MySQL
  • При балансировке нагрузки используются:
    • Взвешенный round robin внутри системы
    • Разные сервера для разных типов запросов
    • Балансировка на уровне ДНС на 32 IP-адреса
  • Большая часть внутреннего софта написано самостоятельно, в том числе:
    • Собственная СУБД (см. ниже)
    • Мониторинг с уведомлением по СМС (Павел сам помогал верстать интерфейс :) )
    • Автоматическая система тестирования кода
    • Анализаторы статистики и логов
  • Мощные сервера:
    • 8-ядерные процессоры Intel (по два на сервер, видимо)
    • 64Гб оперативной памяти
    • 8 жестких дисков (соответственно скорее всего корпуса 2-3U)
    • RAID не используется
    • Не брендированные, собирает компания ТехноОкта
  • Вычислительные мощности серверов используются менее, чем на 20%
  • Сейчас проект расположен в 4 датацентрах в Санкт-Петербурге и Москве, причем:
    • Вся основная база данных располагается в одном датацентре в Санкт-Петербурге
    • В Московских датацентрах только аудио и видео
    • В планах сделать репликацию базы данных в другой датацентр в ленинградской области
  • CDN на данный момент не используется, но в планах есть
  • Резервное копирование данных происходит ежедневно и инкрементально

Волшебная база данных на C

Этому продукту, пожалуй, уделялось максимум внимания аудитории, но при этом почти никаких подробностей о том, что он собственно говоря собой представляет, так и не было обнародовано. Известно, что:

  • Разработана «лучшими умами» России, победителями олимпиад и конкурсов топкодер; озвучили даже имена этих «героев» Вконтакте (писал на слух и возможно не всех успел, так что извиняйте):
    • Андрей Лопатин
    • Николай Дуров
    • **** Левин
    • Арсений Смирнов
  • Используется в огромном количестве сервисов:
    • Личные сообщения
    • Сообщения на стенах
    • Статусы
    • Поиск
    • Приватность
    • Списки друзей
  • Нереляционная модель данных
  • Большинство операций осуществляется в оперативной памяти
  • Интерфейс доступа представляет собой расширенный протокол memcached, специальным образом составленные ключи возвращают результаты сложных запросов (чаще всего специфичных для конкретного сервиса)
  • Хотели бы сделать из данной системы универсальную СУБД и опубликовать под GPL, но пока не получается из-за высокой степени интеграции с остальными сервисами
  • Кластеризация осуществляется легко
  • Есть репликация
  • Если честно, я так и не понял зачем им MySQL с такой штукой — возможно просто как legacy живет со старых времен

Аудио и видео

Эти подпроекты являются побочными для социальной сети, на них особо не фокусируются. В основном это связанно с тем, что они редко коррелируют с основной целью использования социальной сети — общением, а также создают большое количество проблем: видеотраффик — основная статья расходов проекта, плюс всем известные проблемы с нелегальным контентом и претензиями правообладателей. Медиа-файлы банятся по хэшу при удалении по просьбе правообладателей, но это неэффективно и планируется усовершенствовать этот механизм.

1000—1500 серверов используется для перекодирования видео, на них же оно и хранится.

XMPP

Как известно, некоторое время назад появилась возможность общаться на Вконтакте через протокол Jabber (он же XMPP). Протокол совершенно открытый и существует масса opensource реализаций.

По ряду причин, среди которых проблемы с интеграцией с остальными сервисами, было решено за месяц создать собственный сервер, представляющий собой прослойку между внутренними сервисами Вконтакте и реализацией XMPP протокола. Основные особенности этого сервиса:

  • Реализован на node.js (выбор обусловлен тем, что JavaScript знают практически все разработчики проекта, а также хороший набор инструментов для реализации задачи)
  • Работа с большими контакт-листами — у многих пользователей количество друзей на вконтакте измеряется сотнями и тысячами
  • Высокая активность смены статусов — люди появляются и исчезают из онлайна чаще, чем в других аналогичных ситуациях
  • Аватарки передаются в base64
  • Тесная интеграция с внутренней системой обмена личными сообщениями Вконтакте
  • 60-80 тысяч человек онлайн, в пике — 150 тысяч
  • HAProxy обрабатывает входящие соединения и используется для балансировки нагрузки и развертывания новых версий
  • Данные хранятся в MySQL (думали о MongoDB, но передумали)
  • Сервис работает на 5 серверах разной конфигурации, на каждом из них работает код на node.js (по 4 процесса на сервер), а на трех самых мощных — еще и MySQL
  • В node.js большие проблемы с использованием OpenSSL, а также течет память
  • Группы друзей в XMPP не связаны с группами друзей на сайте — сделано по просьбе пользователей, которые не хотели чтобы их друзья из-за плеча видели в какой группе они находятся

Интеграция со внешними ресурсами

Во Вконтакте считают данное направление очень перспективным и осуществляют массу связанной с этим работы. Основные предпринятые шаги:

  • Максимальная кроссбраузерность для виджетов на основе библиотек easyXDM и fastXDM
  • Кросс-постинг статусов в Twitter, реализованный с помощью очередей запросов
  • Кнопка «поделиться с друзьями», поддерживающая openGraph теги и автоматически подбирающая подходящую иллюстрацию (путем сравнивание содержимых тега <title> и атрибутов alt у изображений, чуть ли не побуквенно)
  • Возможность загрузки видео через сторонние видео-хостинги (YouTube, RuTube, Vimeo, и.т.д.), открыты к интеграции с другими

Интересные факты не по теме

  • Процесс разработки близок к Agile, с недельными итерациями
  • Ядро операционной системы модифицированно (на предмет работы с памятью), есть своя пакетная база для Debian
  • Фотографии загружаются на два жестких диска одного сервера одновременно, после чего создается резервная копия на другом сервере
  • Есть много доработок над memcached, в.т.ч. для более стабильного и длительного размещения объектов в памяти; есть даже persistent версия
  • Фотографии не удаляются для минимизации дефрагментации
  • Решения о развитии проекта принимают Павел Дуров и Андрей Рогозов, ответственность за сервисы — на них и на реализовавшем его разработчике
  • Павел Дуров откладывал деньги на хостинг с 1 курса :)

Подводим итоги

В целом Вконтакте развивается в сторону увеличения скорости распространения информацию внутри сети. Приоритеты поменялись в этом направлении достаточно недавно, этим обусловлено, напимер, перенос выхода почтового сервиса Вконтакте, о котором очень активно говорили когда появилась возможность забивать себе текстовые URL вроде vkontakte.ru/ivan.blinkov. Сейчас этот подпроект имеет низкий приоритет и ждет своего часа, когда они смогут предложить что-то более удобное и быстрое, чем Gmail.

Завеса тайны насчет технической реализации Вконтакте была немного развеяна, но много моментов все же остались секретом. Возможно в будущем появится более детальная информация о собственной СУБД Вконтакте, которая как оказалось является ключом к решению всех самых сложных моментов в масштабируемости системы.

http://www.insight-it.ru/masshtabiruemost/arkhitektura-vkontakte/

Построение дерва с помощью рекурсии

Бывает часто, что нужно вывести дерево с неограниченной глубиной.

Структура базы:

Перейдём к коду. Первым делом создадим базу данных и наполним её деревом.
Дамп базы данных:

CREATE TABLE catalogue
(id INT UNSIGNED AUTO_INCREMENT,
title VARCHAR (50),
pid INT UNSIGNED,
PRIMARY KEY(id));

INSERT INTO catalogue (title, pid) VALUES ('Раздел 1', 0);
INSERT INTO catalogue (title, pid) VALUES ('Раздел 2', 0);
INSERT INTO catalogue (title, pid) VALUES ('Раздел 3', 0);
INSERT INTO catalogue (title, pid) VALUES ('Раздел 4', 0);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.1', 1);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.2', 1);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.3', 1);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 2.1', 2);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 2.2', 2);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.1.1', 5);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.1.2', 5);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 1.1.2.1', 11);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 3.1', 3);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 4.1', 4);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 4.2', 4);
INSERT INTO catalogue (title, pid) VALUES ('Подраздел 4.2.1', 15);

Сам исполняющий файл index.php


<?php
include( "dbopen.php" );

 function ShowTree($ParentID, $lvl) {

 global $link;
 global $lvl;

 $lvl++;

 $sSQL = "SELECT id, title, pid FROM catalogue WHERE pid = " . $ParentID . " ORDER BY title";

 $result = mysql_query($sSQL, $link);

 if (mysql_num_rows($result) > 0) {
 echo("<UL>\n");
 while ( $row = mysql_fetch_array($result) ) {
 $ID1 = $row["id"];
 echo("<LI>\n");
 echo("<A HREF=\"" . "?ID=" . $ID1 . "\">" . $row["title"] . "</A>" . "&nbsp;&nbsp;\n");
 ShowTree($ID1, $lvl);
 $lvl--;
 }
 echo("</UL>\n");
 }

 }

ShowTree(0, 0);

mysql_close($link);

?>

dbopen.php — просто подключается к БД


<?php

 $hostName = "localhost";
 $userName = "root";
 $password = "";
 $databaseName = "4";

 if (!($link=mysql_connect($hostName,$userName,$password))) {
 printf("Ошибка при соединении с MySQL !\n");
 exit();
 }
 if (!mysql_select_db($databaseName, $link)) {
 printf("Ошибка базы данных !");
 exit();
 }

?>

И результат работы: Отмечу, что если это будет использоваться для меню — желательно применить кэширование! Скачать пример:

http://vazelin.org.ua/wp-content/plugins/downloads-manager/img/icons/default.gif download: phptree (1.09KB)
added: 05/10/2010
clicks: 110
description:
Автор: http://www.codenet.ru/webmast/php/tree.php

PHP удалить всей файлы из дериктории

Как-то мне нужно было очистить папке от всех файлов.

Используя перебор с помощью функции glob() доступа на удаление сервер не давал. Даже прописывая chown, chmod результата не было.

Но удалось найти полезную функцию, которая делает это отлично.

Данная функция может быть полезна для ручной очистки кэша:

сама функция:


function delete_directory($dirname) {
 if (is_dir($dirname))
 $dir_handle = opendir($dirname);
 if (!$dir_handle)
 return false;
 while($file = readdir($dir_handle)) {
 if ($file != "." && $file != "..") {
 if (!is_dir($dirname."/".$file))
 unlink($dirname."/".$file);
 else
 delete_directory($dirname.'/'.$file);
 }
 }
 closedir($dir_handle);

 return true;
 }

Вызов функции с передачей папки, которую нужно очистить:


$path = dirname(dirname(dirname(__FILE__))). '\cache\global';
 delete_directory($path);

substr +utf-8 +php

при работе функции substr с кодировкой utf-8 часто можно получить «левые» символы.

Чтобы это избежать нужно использовать эту функцию:


function myutf8_substr2($str,$from,$len){
# utf8 substr
return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$from.'}'.
'((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s',
'$1',$str);
}

Пример использования:
$prname=myutf8_substr2($prname,0,»23″)

Найдено тут: http://www.eco-money.ru/forum/topic?id=7

Либо, Multibyte String Functions


string  <strong>mb_substr</strong> (  string  <tt>$str</tt> ,  int  <tt>$start</tt> [,  int  <tt>$length</tt> [,  string  <tt>$encoding</tt> ]] )

Используем Google Maps у себя на сайте

Первое, что нам нужно — получить ключ для работы. Ключ получаем по ссылке http://code.google.com/intl/ru/apis/maps/signup.html

На сайте, мне нужно было отображать местоположение человека, который ввёл адрес.

Сам код:


// вставляем полученный ключ для домена.

<script src="http://maps.google.com/maps?file=api&amp;v=3&amp;sensor=true&amp;key=" type="text/javascript"></script>

<script>

 var map = null;
 var geocoder = null;

 function initialize() {
 if (GBrowserIsCompatible()) {
 map = new GMap2(document.getElementById("map_canvas"));
 map.setCenter(new GLatLng(50.449744, 30.523968), 7);
 geocoder = new GClientGeocoder();
 }
 if (geocoder) {
 address = "<? $new_person -> EchoContacts2();?>";
 geocoder.getLatLng(
 address,
 function(point) {
 if (!point) {

 } else {
 map.setCenter(point, 16);
 var marker = new GMarker(point);
 map.addOverlay(marker);

 }
 }
 );
 }
 }
 </script><body onload="initialize()" onunload="GUnload()">
 <p>Местоположение на карте</p>
 <div id="map_canvas" style="width: 271px; height: 210px"></div>
 </body>

$new_person -> EchoContacts2(); — выводит для карты адрес человека. Смысл этого простой: получить из базы адрес. Для вас это место будет другим.

Если адреса нет — выводит центр Киева

Работа в PHP с шаблонами {templates}

Класс шаблонов это незаменимая часть в форуме, гостевой, чате и т.д. Это класс прост, причём очень прост. Объясню основные функции: загрузка шаблона, обработка в нём переменных и выход шаблона. Давайте рассмотрим подробнее:

<?php

class template # создали класс

{ # зададим переменные

var $data = array(); # переменная для шаблонов

var $root = '.'; # каталог для шаблонов

var $ext = '.tpl'; # расширение для шаблонов

var $da_vr = array(); # переменная для преобразованых шаблонов

// Класс создан, далее формируем функции:

function template($dir,$ext)

{

if(is_dir($dir)){$this -> root = $dir;}

else{die('Ошибка! <b>'.$dir.'</b> - это не директория!');}

$this -> ext = $ext;

}

// Эта функция выполниется сразу после создания класса, поэтому при создании надо

// указывать директорию и расширения шаблонов (см. ниже). Далее надо загрузить шаблон:

function load($name)

{

$nn = $name;

$dir = $this -> root;

$ext = $this -> ext;

$name = $dir.'/'.$name.$ext;

if(!is_file($name)) {die('Ошибка <b>'.$name.'</b> - это не файл!');}

$fp = fopen($name,'r');

$data = fread($fp,filesize($name));

fclose($fp);

$this -> data[$nn] = $data;

$this -> da_vr[$nm] = $data;

}

// В этой функции мы считали шаблон через fread и запихнули его в две переменных:

// da_vr и data. При загрузке шаблона надо указывать имя шаблона без расширения

// (см.ниже). Далее преобразовываем переменные:

function vars($nm,$vars = array())

{

$data = $this -> data[$nm];

while(list($id,$var) = each($vars))

{

global $$vars[$id];

$data=str_replace('{'.$vars[$id].'}',$$vars[$id],$data);

}

$this -> da_vr[$nm] = $data;

}

// Тут мы преобразовали переменные и загнали в переменную da_vr. И осталось вывести

// шаблон:

function out($name)

{

$ret = $this -> da_vr[$name];

$this -> da_vr[$name] = $this -> data[$name];

return $ret;

}

}

Обясню как работать с классом. Допустим у нас есть шаблон body.tpl в директории data. Его содержимое:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

<head>

<title> {title} </title>

</head>

<body bgcolor={bgcolor}>

{text}

</body>

</html>

Работа с классом:

include('template.php'); # включили класс

# Зададим переменные #

$bgcolor = '#CCFFCC';

$text = 'Тест класса!';

$title = 'ТЕСТ!';

$tpl = new template('./data','.tpl'); # создали объект, задали каталог и расширение

$tpl -> load('body'); # зашрузили шаблон

$tpl -> vars('body',array('text','title','bgcolor')); # указали какие переменные преобразовать, они должны быть заданы зарание

echo $tpl -> out('body'); # вывели шаблон

По следам: http://php.su/articles/?cat=examples&page=006

Автор:  Андрошук Александр