Просьба оставить комментарий





Если вам понравился или не понравился топик. Я что то забыл или не дописал, то вы можете оставить свой комментарий и я постараюсь исправить это в ближайшее время.

четверг, 27 октября 2011 г.

Устранение ошибки Ошибка 500 (Internal Server Error) при использовании .htaccess для принудительной загрузки файла

Ошибка 500 (Internal Server Error) пишет что ошибка описана в error.log я не нашел

Данная ошибка возникла при переносе с хостинга на собственный VDS сайта mcgrp.ru. Ранее была статья для принудительной загрузки файлов при нажатии по ссылке, вот собственно продолжение этой темы.

Ошибка возникает при сборке Апач по умолчанию. Решение этой проблемы подключение доп модуля, аналогично подключению нового сайта, только вместо команды a2ensite пишем в консоли a2enmod headers

headers - модуль как раз отвечающий за эту функцию, список других модулей доступных для подключения можно посмотреть в каталоге mods-available

понедельник, 24 октября 2011 г.

Backup файлов конфигураций оборудования Cisco по расписанию

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

Проблему решает следующий скрип:

#!/usr/bin/perl
use Net::Telnet ();
use Net::Telnet::Cisco;
use Mail::Sendmail;

my @arrCiscoAddress = ('xxx.yyy.zzz.www',
               'xxx.yyy.zzz.www',
               'xxx.yyy.zzz.www');

    $size = @arrCiscoAddress;
    print "Devices Ciscos: ".$size."\n";

my $ip="";
my $usernameCisco="login";
my $passwordCisco="pass";
my $usernameDlink="";
my $passwordDlink="";
my $passwordDlink2108="";
my $devType=0;   # 0 - нет; 1 - Cisco; 2 - Dlink3026; 3 - 2108
my $Cisco=0;
my $Dlink3026=0;
my $Dlink2108=0;
my $Unknown=0;
my $is_login=0;
my $is_cmd=0;
my $res="";
my $log_fail="";
my $dead="";
my $alive="";
my $log="";
my $log_t="";
my $t;
my $tmp;
my $mu;

# ----------------------------------------------------------------

$txt = "--- Config download script by dfox  ---\n";
print $txt; $log=$log.$txt;
$txt = "Initialization...";
print $txt; $log=$log.$txt;

$txt = "\t\tOK!\n----------------------------\n";
print $txt; $log=$log.$txt;

# ----------------------------------------------------------------
# Пробегаем по списку адресов
# ----------------------------------------------------------------
$b3 = "225";
        for($k=0; $k<=$size-1;$k++)
        {
        $ip=$arrCiscoAddress[$k];

        $txt = "trying $ip...";
        print $txt; $log=$log.$txt;

        $sessionnoc = new Net::Telnet(Timeout => 5, Errmode=>"return");
                $sessionnoc->open(Host=>"server.ru", Port => 23);
       
                $session = new Net::Telnet(Timeout => 5, Errmode=>"return");
                $session->open(Host=>$ip, Port => 23);
       
                $msg=$session->errmsg;
                if(!$msg)
                {
                $txt = "\t\tOK!\n";
                print $txt; $log=$log.$txt;

                        $alive=$alive.$ip."\n";
                         
                #------------------------------------------------------
                        # проверяем что за девайс
                #------------------------------------------------------
                $tmp="";
                $tmp=$session->get;
                $devType=0;
                # Cisco
                if (index($tmp,"")>=0)
                {
                        $devType=1;
                        $txt="Device type - Cisco\n";
                };
                # Dlink3026
                if (index($tmp,"DES-3026")>=0)
                {
                        $devType=2;
                        $txt="Device type - Dlink-3026\n";
                };
                # Unknown
               
                #if ($devType==0)
                #{
                #        ++$Unknown;            
                #        $txt="Device type - Unknown\n";
                #};
                #print $devType;
                #print $txt; $log=$log.$txt;
                #if($devType==0){next;};

                #------------------------------------------------------
               
               
                # логинимся исходя из типа девайса
                #------------------------------------------------------
                $txt="Logging on...   ";
                print $txt; $log=$log.$txt;
                # Cisco
                if ($devType==1)
                {
                        $t=Net::Telnet::Cisco->new(Errmode=>"return",Timeout=>20,Host=>$ip,Input_log=>'tmp_cisco_in.txt',Output_log=>'tmp_cisco_out.txt');
                        if ($t->login($usernameCisco,$passwordCisco)){$is_login=1;} else{$is_login=0;};
                };
               
                # Dlink3026
                if ($devType==2)
                {              
                        $t=Net::Telnet->new(Timeout => 20, Prompt => '/#/', Host=>$ip, Errmode => "return",Input_log=>'tmp_dlink.txt',Output_log=>'tmp_dlink1.txt');                                   
                        if ($t->login($usernameDlink,$passwordDlink)) { $is_login=1; } else {$is_login=0;};
                };
               

                if($is_login>0){$txt="\t\tOK!\n";} else{$log_fail=$log_fail."$ip\n",$txt="\t\tfailed!\n";$log_t=$log_t."$ip\tlogin_failed!!\n";};      
               
                print $txt; $log=$log.$txt;
                if($is_login==0){next;};
                         
                #------------------------------------------------------
                        # делаем дело исходя из типа девайса
                #------------------------------------------------------
                $txt="Uploading cmd...";
                print $txt; $log=$log.$txt;
                $is_cmd=0;     
                # Cisco
                if ($devType==1 && $is_login>0)
                {
                        if(!($t->is_enabled)) {$t->enable($passwordCisco);};
                        $t->cmd('terminal length 0');
            $mu = $k+1;
                        if (@lin=$t->cmd("copy running tftp://ftp.ftp.ftp.ftp/cisco_conf/$mu-".$ip."-conf.txt \n\n\n"))
                        {
                        $t->cmd("copy vlan.dat tftp://ftp.ftp.ftp.ftp/cisco_conf/$mu-".$ip."-vlan.dat\n\n\n");
                        $is_cmd=1;
                        #$res=@lin;
                        ++$Cisco;
                        $t->cmd("logout");
                        $t->close;
                        }
                        else {$is_cmd=0;};
                };

                # Dlink3026
                if ($devType==2 && $is_login>0)
                {                      
                        $t->cmd('dis cli');
                        @lin=$t->cmd("upload config ftp.ftp.ftp.ftp config.dlink.txt");
                        if (@lin)
                        {
                        $is_cmd=1;
                        #$res=@lin;
                        ++$Dlink3026;
                        $t->cmd("logout");
                        $t->close;
                        }
                        else {$is_cmd=0;};
                };
               
                if($is_cmd)
                {
                        $txt="\t\tOK!\n$res\n";
                        $log_t=$log_t."$ip\tOK!\n";
                }
                else
                {
                        $txt="\t\tfailed!\n";
                        $log_t=$log_t."$ip\tfailed!\n";
                }
                print $txt; $log=$log.$txt;                    
                $t->close;
        }
        else
        {
                $txt = "\t\tfailed!\n";
                print $txt; $log=$log.$txt;
                        $dead=$dead.$ip."\n";
                $log_t=$log_t."$ip\ttelnet_failed!!\n";

        }
        # закрываем сессию
        $session->close;
        }


# ----------------------------------------------------------------
# Архивируем и удаляем конфиги. 
# ----------------------------------------------------------------

#system ("/usr/home/scr/scripts/arch_conf");

# ----------------------------------------------------------------
# шлем почту о резалтах
# ----------------------------------------------------------------
%mail =
(
        To      => 'admins@domain',
        From    => 'backups@domain',
        Subject => 'Service report about BACKUP',
        Message => "Backup devices:\nCisco = $Cisco\n*************\n$log_t\n$log\n",
        SMTP    => '**********'
);
       
sendmail(%mail) or die $Mail::Sendmail::error;
print "OK. Log says:\n", $Mail::Sendmail::log; 
# ----------------------------------------------------------------

В этом скрипте можно указать список ip адресов сетевых устройств конфиги с которых надо сливать по расписанию. Есть минус в том что логин пароль хранятся в нем в не зашифрованном виде, но это можно доработать. Бекапятся как cisco так и dlink, к которым есть доступ по телнет, ну и в конце отправляется отчет по email. Также на сервере где будет прописываться скрипт(используется у меня на  Debian 6) нужно подключить использование следующего пакета Net::Telnet. Так как писалось давно уже и не помню как ставить, ну думаю разберетесь. Сами скрипты заливаются на tftp сервер.

Способы ускорения индексации сайта поисковыми системами

У каждого оптимизатора есть собственный набор способов оптимизации. В этом топике я опишу свои приемы проверенные на практике для ускорения индексации сайта. Эти способы работают на 2х основных поисковых системах Яндекс и Гугл.

1. Очень важный пункт. Избегание или минимизация ошибок HTML. Для проверки можно воспользоваться сервисом http://validator.w3.org/.
2. Правильные коды ответа сервера на страницах сайта. Для проверки какой код возвращает страница, можно воспользоваться этим сервисом http://inettools.net/answer-http-server.html
3. Использовать только один вид домена либо с www либо без www, естественно лучше использовать без www, так как www все таки поддомен-алиас на основное имя домена. В файле .htaccess соответственно нужно сделать 301 редирект с домена с www на домен без.
4. Правильно составить файл robot.txt, лучше тоже использовать онлайн сервис с указанием большого количества роботов + с указанием расположения sitemap.xml
5. Избегать повторения заголовков страниц, да и всех метаданных.
6. Использовать кэширование на стороне сервера для ускорения работы. Гугл учитывает скорость загрузки сайтов при ранжировании. http://avesadmin.blogspot.com/2011/10/phpobstart.html

7. Генерировать файл sitemap.xml
8. Использование логичных и релевантных блоков с ссылками на соседние и похожие страницы(Внутренняя перелинковка)
9. Отказаться от различных блоков не желательной рекламы Попандеров, кликандеров, либо использовать их только в тех случаях когда выполняется какой либо скрипт с проверкой на человечность, например каптча.
10. Наращивание ссылочной массы, желательно естественной.
11. Ну и естественно стараться использовать уникальный контент.

Самый простой способ кэширования на стороне сервера php(ob_start())

При написании небольших проектов можно сильно не беспокоиться за, то как нерационально написан скрипт с точки зрения использования процессора и баз данных, допустим если количество посетителей в день не превышает 10-20 человек в день. Но при росте количества посетителей со временем могут происходить сбои работе из за большого количества запросов хостер может просто ограничивать вам ресурсы и следовательно часть скрипта просто не будет выполнена. Мой хостер при большой загрузке блокировал запросы к базе данных и вместо текста и полей не выводилось пустое пространство. Для решения этой проблемы я проделывал работы:
1. Оптимизация кода на php
2. Укорачивание запросов, например выбор только одного поля или нескольких, где использовалось (*).
3. Раз в сутки выполнял запрос с задействованием большого количества полей и условий и записывал в отдельной таблице базы данных результат и выводил только его.
4. Задействовал в самом нагруженном месте функцию php ob_start(). О ней подробнее ниже.

Что делает ob_start()
Функция позволяет перенаправить вывод результата php скрипта в отдельную переменную:

<?php
ob_start(); Стартуем использование механизма
echo "ok"; Делаем вывод
ob_end_flush(); Эта команда выводит весь результат который был до нее и между функцией ob_start(); в виде html в тело документа.
?>

Т. е. в результате работы данного куска кода получиться результат аналогичный простому использованию одной команды echo:

<?php
echo "ok";
?>

Если в первом случае не использовать функцию ob_end_flush(); , то результат выведен не будет, а по завершению работы скрипта просто произойдет очищение буфера.

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

<?php
//Получаем значение URI(То есть часть строки адреса без домена)

if($_SERVER['REQUEST_URI']!="/")
{
//Загоняем в переменную
$request = $_SERVER['REQUEST_URI'];
//Вырезаем символ слеша
$request = urldecode(str_replace('/', '', $request));
}



Проверяем на существование файла кэша
$filename_cache = 'cache/'.$request;

if (file_exists($filename_cache))
{
//Если существует то просто выводим на экран
$handle = fopen($filename_cache, "r");
$contents_from_cache = fread($handle, filesize($filename_cache));
fclose($handle);
echo  $contents_from_cache;
}
else
{
//Если нет то исполняем скрипты с результатами, запросы к базе данных, в общем, все что //нужно.
echo "Строка которая будет записана в кэш файл на сервере";

//******************************************************//


//Открываем файл на запись в папке cache сервера(естественное ее надо создать)
$file = fopen ("cache/".$request,"w");
//Приравниваем(присваиваем) значение буфера переменной
$content_cache = ob_get_contents();
if (!$file)
{
//Проверка на всякий
echo("Ошибка открытия файла");
}
else
{
//Если файл доступен на запись пишем
fputs ( $file, $content_cache);
}
fclose ($file);
//******************************************************//

ob_end_flush(); // Просто выводим содержимое буфера
 }

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

В части скрипта где происходит чтения файла можно использовать так же оператор include, это по желанию.

При использовании в связки с ЧПУ, будет вполне симпатично выглядеть.

пятница, 21 октября 2011 г.

Принудительная загрузка файлов (например pdf)

Иногда возникает потребность принудительно открывать окно загрузки файла для пользователя, например при ссылке на файлы pdf, чтобы пользователь скачивал его себе на компьютер, а не просматривал с сервера в окне браузера. Например это необходимо при скрытии реального пути до файла на сервере для защиты от парсинга контента, когда вы сначала загружаете файл со стороннего сервера, например файлсервера, и закачиваете его в папку с именем сессии пользователя. Так же это защищает от того, что пользователи будут скачивать файл по статической ссылке, вместо того чтобы заходить на ваш сайт и при желании щелкать по рекламке.

Собственно сама технология очень проста на практике, допустим папки с именем сессии пользователя создаются на сервере сайта в папке temp/ , то есть temp/45asd454sfdg123/file.pdf , в таком случае достаточно в папке temp создать файл .htaccess со следующим содержимым

    <files *.mp3>
    forceType application/octet-stream
    Header set Content-Disposition attachment
    </files>

   <files *.pdf>
    forceType application/octet-stream
    Header set Content-Disposition attachment
    </files>
   
    <files *.doc>
    forceType application/octet-stream
    Header set Content-Disposition attachment
    </files>
   
    <files *.txt>
    forceType application/octet-stream
    Header set Content-Disposition attachment
    </files>

    <files *.jpg>
    forceType application/octet-stream
    Header set Content-Disposition attachment
    </files>

Вложенные в эту папку каталоги с именем сессии просто наследуют инструкции родительской и присваивают эти свойства.

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

суббота, 15 октября 2011 г.

Рабочий и простой способ ЧПУ(Человеко понятых url адресов)

Мой рабочий способ создания ЧПУ на примере сайта mcgrp.ru. Структура сайта сделана по рекомендациям для вэбмастеров гугла и яндекса. Все станицы доступны в 3 кликах от главной, в данном случае даже 2х. Идея дянного чпу состоит в составлении адреса станицы на основе названия бренда или на основе бренда+названия модели с расширением html.

Основные задачи для создания подобных ссылок:

1. Так как названия состоят из кириллических символов, то следовательно необходимо вводить функции преобразование в латиницу.

2. По рекомендациям для разделения слов в ссылках рекомендуется использовать в качестве разделителя дефис("-"). И всяко не стоит использовать пробел. Символ нижнего подчеркивания("_") использовать не стоит, так как он используется в роли оператора объединения, а не разделения.

3. Перехват этих ссылок и подстановка параметров перед загрузкой основной страницы. То есть создать иллюзию того, что были переданы параметры методом Get или Post. Это требуется только в том случае если необходимо гарантировать доступность, по старым ссылкам. Да и в общем логичное поведение скрипта для возможно доработки.

4. Перевод на такие ссылки рекомендуется переводить полностью все возможные разделы и ссылки, если часть ссылок у вас останется в формате ?param1=value1&param2=value2, то возможно возникнуть проблемы вида page1.html?param1=value1&param2=value2 что негативно скажется на отношение поисковых систем к вашему сайту. И часть страниц может отправиться в "сопли".


Этап 1
Основа технологии ЧПУ является mod_rewrite вэбсервера Apache. Для начала следует убедиться, что данный модуль подключен. Далее следует внесение изменение в файл .htaccess в корне вашего сайта.

Пример файла:

1. RewriteEngine On
2. RewriteBase /

3. RewriteCond %{HTTP_HOST} ^www.mcgrp.ru$ [NC]
4. RewriteRule ^(.*)$ http://mcgrp.ru/$1 [R=301,L]

5. RewriteCond %{REQUEST_FILENAME} !-f
6. RewriteCond %{REQUEST_FILENAME} !-d
7. RewriteRule . / [L]

Очень важно соблюдать подобную последовательность.

Строка 1 включает модуль mod_rewrite.
Строка 2 указывает базу с которой надо отслеживать (вырезать адрес страницы).

Строки 3,4 отвечают за редирект сайта с www на сайт без www их следует указать до строк 5, 6 иначе будут наблюдаться глюки.


Этап 2
Теперь необходимо как то разбирать данные строки. Для этого предварительно необходимо подготовить соответствие в базе данных для каждой строки. Для этого нужно добавлять параметр в специальное поле при добавлении строки либо написать генератор для ручного запуска или по расписанию. Если ваш сайт уже большой, то генератор нужно будет написать и добавить поле в БД.

Для преобразования из кириллицы в латиницу, а также замены спецсимволов я использую 2 функции:

1.

function NormalizeStringToURL2( $s )
{
    $r = array('а','б','в','г','д','е','ё','ж','з','и','й','к','л','м', 'н','о','п','р','с','т','у','ф','х','ц','ч', 'ш', 'щ', 'ъ','ы','ь','э', 'ю', 'я',' ');
    $l = array('a','b','v','g','d','e','e','g','z','i','y','k','l','m','n', 'o','p','r','s','t','u','f','h','c','ch','sh','sh','', 'y','y', 'e','yu','ya','-');
    //$s = str_replace( $r, $l, strtolower($s) );
    $s = mb_eregi_replace("[^\w\-]","-",$s);
    $s = preg_replace("/\-{2,}/",'-',$s);
    return trim($s,'-');
}

2.

function translitIt($str)
{
    $tr = array(
        "А"=>"a","Б"=>"b","В"=>"v","Г"=>"g",
        "Д"=>"d","Е"=>"e","Ж"=>"j","З"=>"z","И"=>"i",
        "Й"=>"y","К"=>"k","Л"=>"l","М"=>"m","Н"=>"n",
        "О"=>"o","П"=>"p","Р"=>"r","С"=>"s","Т"=>"t",
        "У"=>"u","Ф"=>"f","Х"=>"h","Ц"=>"ts","Ч"=>"ch",
        "Ш"=>"sh","Щ"=>"sch","Ъ"=>"","Ы"=>"yi","Ь"=>"",
        "Э"=>"e","Ю"=>"yu","Я"=>"ya","а"=>"a","б"=>"b",
        "в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"j",
        "з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
        "м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
        "с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
        "ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"y",
        "ы"=>"yi","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya",
        " "=> "-", "."=> "", "/"=> "-", "--"=> "-", "---"=> "-", "----"=> "-", "-"=> "-"
    );
    return strtr($str,$tr);
}

Использую я их так.
$title = "Какой то title";
$cp = translitIt(NormalizeStringToURL2($title))).".html";
В $cp создается строка в формате подходящем для использования в ЧПУ.
Пример: kakoy-to-title.html

Этап 3

После того как все строки добавлены в БД, можно начинать прикручивать ЧПУ к движку сайта. Для этого надо создать скрипт который при обращении по адресу mcgrp.ru/kakoy-to-title.html подсовывал обрабатывающему скрипту параметры, которые в обычном варианте без чпу передавались в формате mcgrp.ru/index.php?param1=value1&param2=value2

 Создадим файл cp.php и подключим его в самом начале скрипта после подключение к базе данных.

Файл cp.php

if($_SERVER['REQUEST_URI']!="/")
{
$request = $_SERVER['REQUEST_URI'];
$request = urldecode(str_replace('/', '', $request));
    $result = mysql_query("SELECT * FROM имя_таблицы WHERE cp='".$request."';");
        while ($row = mysql_fetch_assoc($result)) {
        if($row['cp'] == $request)
            {
            $param1 = $row['value1'];
            $param2 = $row['value2'];
            $ans = "yes";
            }
        }
}

PS:

Если количество страниц слишком велико, рекомендую сначала проделать пункт 2,3 потом уже вносить изменения в файл .htaccess.
Продумайте план по полному переходу на ЧПУ так как поисковые системы могут наказать за дублирование заголовков, если страницы доступны по 2 урл с одинаковым содержимым.
Старайтесь выбирать строку для генерации ЧПУ с уникальным содержимым, бывают ситуации из за плохого продумывания строки ЧПУ, она генерировалась с одинаковым текстом и следовательно 2 разных записи в БД указывали на 1 страницы. Чтобы избежать подобного при навигации по разделам с большим количеством страниц можно воспользоваться таким форматом page9-razdel1.html и при обработке обрезать и извлекать номер страницы preg_match регуляркой.