СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H Пишу программы на незнакомом мне языке в черновиках



Не уверен, что это хорошая идея — признаваться в собственном непрофессионализме. Люди работают над своим имиджем, создают портфолио, зарабатывают авторитет и дорожат им. Я же легко признаюсь в свом полном непрофессионализме и даже авантюризме: я довольно часто рискую писать программы на неизвестных мне языках программирования. Однажды один из заказчиков спросил меня, как я пришел в разработку на java для Андроид, а я ему по глупости ответил: ну как, как? Да ведь if-ы и else везде одинаковые! Неудачная шутка. Впрочем, программирование для Андроид — это всего лишь эпизод.

Сейчас я расскажу совсем другую историю. История о том, как и почему я решился писать свою первую программу на PHP и MYSQL (SQL это ведь тоже язык? или нет?).

История совершенно практическая. У меня есть сайт, ему уже 7 лет.
Сайт когда-то давно был сделан на CMS Joomla 1.5. Туда было вложено много времени, труда и души. Время шло, нужно было делать апдейты, но это было очень трудно, так как по некоторые компоненты были несовместимы с новой Джумлой 1.6/1.7 а потом уже и 2.5. Для перехода с Joomla 1.5 в Joomla 2.5 так же нужно было менять шаблон. В общем, с горем пополам, я смог сделать апдейт, но было уже поздно. Как раз в то время Joomla 2.5 уже перестала поддерживаться в связи с выходом Joomla 3. Печальная история — все время нужно играть в догонялки.

Необходимость перейти на Joomla 3 очевидна уже давно. Но как это сделать, если есть компоненты, которые нельзя вот так просто взять и заменить? Один из важных компонентов моего сайта — система для публикации файлов для скачивания DOCman. Этот DOCman всегда было трудно апгрейдить, но последняя капля — он стал платным. Вроде и стоит не очень дорого, но надоело. Перемен — требуют наши сердца.

Нет, сперва я конечно потратил уйму времени на поиски более свежего DOCman, который все таки можно поставить на сайт. Не нашел. Зато нашел очень похожий по функциональности другой компонент PhocaDownload.

Можно попробовать его использовать. Вот только как сделать миграцию?

Опять трата времени на поиск «мигратора».



И ведь нашел, только выглядит очень подозрительно, это java программа, которая у меня почему-то не заработала. Тогда у меня промелькнула мысль: а что если самому написать скрипт для переноса данных из базы DOCman в базы PhocaDownload?

Пожалуй, тут нужно описать рамки моих знаний связанных с веб-технологиями.

Первое. Я умею пользоваться Sypex Dumper и phpmyadmin на уровне домохозяйки. Ну то есть я могу сделать экспорт или импорт какой нибудь базы данных или таблицы. Могу смотреть базы данных и делать какие нибудь простые изменения в записях. Могу по ошибке дропнуть базу. Ну вот так — всего понемножку.

Второе. Понятно, что экперименты нельзя ставить на живом сайте. Я это и не буду делать и не собираюсь. У меня есть виртуальная машина с убунтой, где развернут apache+php+mysql. Ставил сам по обычным инструкциям из этих наших интернетов — инструкций много. Копию живого сайта я могу развернуть из архива в локальной виртуальной машине примерно минут за десять. Это важно, так как я понимаю, что если я буду писать в базы и чего-то по ошибке сломаю, то придется повторять все сначала: все сносить, и разворачивать с архива заново. Пять-десять минут на эксперимент с чистого листа — мне кажется, что это терпимо. Я даже написал простейший скрипт, который бы раскрывал архив:

#!/bin/sh
rm public_html -rf
unzip arch.zip
cp configuration.php public_html/
chown www-data:www-data public_html -R

Правда тут я поленился, скрипт только расжимает архив, а мог бы еще и базу MySql импортировать. Импорт делаю вручную — дело то не хитрое.

Третье. Я примерно представляю себе, что такое html/css/js, но, думаю, на уровне junior. Так же и с php. На php я знаю, что if-ы и else они примерно как в c/c++, с фигурными скобками, а c/c++ я думаю, что знаю (надеюсь, что знаю). Еще, про php я помню, что там есть echo «asdfasdf», которое и формирует текст html, который потом отображается в браузере. Пожалуй это и все.

Некоторое время я рассматривал таблицы баз данных докмэна и пфоки в phpmyadmin и сравнивал их. Структуры похожи, но не одинаковы. У меня даже был соблазн экспортировать таблицы в CSV и затем в экселе переставить столбцы в нужном порядке. Однако эти мысли я быстро прогнал: ведь результат ручных манипуляций трудно повторить в точности. Если я буду формировать в экселе новую таблицу и потом при импорте что-то пойдет не так, то опять все заново делать и опять можно где-то ошибиться. Если сделать скрипт, то его можно многократно попробовать на чистой базе, можно многократно отработать технологию миграции с DOCman на PhocaDownload.

Кратко, задачу можно изложить так:
  1. в таблице jx25_docman_categories есть список категорий документов, его нужно переместить в таблицу jx25_phocadownload_categories, но только некоторые поля имеют другие имена или есть поля, которые не имеют прямого соответствия (тогда их думаю/надеюсь можно просто пропустить).
  2. второй этап полностью аналогичен первому: нужно взять записи из таблицы jx25_docman и перенести их в jx25_phocadownload, опять некоторые поля называются иначе или их нет там или их нет тут.
  3. просмотреть все статьи и найти ссылки на скачивание DOCman и переделать их в ссылки на скачивание PhocaDownload. Этот этап вероятно самый сложный.

Вот с этими мыслями я и взялся за дело.

Как программировать на языке, которого не знаешь? Думаю ответ понятен всем: нужно гуглить или яндексить. По своему опыту скажу, что лучше гуглить и лучше на английском языке. Ответов на вопросы больше всего в stackoverflow или, скажем, на w3schools.com, и ответы там, конечно на английском.

Например, задаю вопрос: «read mysql table php»:



Первые же ссылки гугла уже сразу дают ответ на мой вопрос. Я создаю php файл conv.php в корне копии моего сайта в локальной виртуальной машине. Мне нужен файл, который я могу редактировать и который может запускать мой web сервер Apache:

cd /var/www/html/public_html/
sudo touch conv.php
sudo chown www-data:www-data conv.php
sudo chmod a+w conv.php

Теперь файл можно редактировать. Правило написания программ на неизвестном языке программирования такое: от простого к сложному маленькими шагами. Шаг первый — это вообще убедиться, что простейшая программа на php запускается и выдает то, что нужно:

<?php
echo "<!DOCTYPE html>";
echo "<html><head>";
echo "</head><body>";

echo "Hello World! Привет!";

echo "</body>";
echo "</html>";
?>

Из браузера подключаюсь к своей виртуальной машине и проверяю результат:



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

<?php
echo "<!DOCTYPE html>";
echo "<html><head>";
echo "</head><body>";

echo "<p>Hello World! Привет!</p>";

$con=mysqli_connect("localhost","user","password","database");

// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

$result = mysqli_query($con,"SELECT * FROM jx25_docman_categories");

while($row = mysqli_fetch_array($result))
{
    $id = $row['id'];
    $parent_id = $row['parent_id'];
    $title = $row['title'];
    $name = $row['name'];

    echo "<p>".$id."*".$parent_id."*".$title."*".$name."</p>";
}

mysqli_close($con);

echo "</body>";
echo "</html>";
?>


Понятно, что код из статей гугла приходится копировать не слово в слово, но слегка модифицировав под свои нужды. В процессе адаптации кода вписываю в функцию mysqli_connect свои имя пользователя и пароль к базе и название своей базы. Попутно приходится гуглить всякие странные вопросы, например, «how to echo integer var on php», или «join strings php». Сохранил текст программы php — теперь попробую результат в браузере:



Оопс… Что-то пошло не так. Проблема с кодировкой, только кодировкой чего? У меня вроде бы в самой первой программе слово «Привет» верно отображалось, то есть видимо проблема не в странице, а в чтении из базы? Опять гуглим. Похоже где-то нужно вставить строку:

mysqli_query($con,"SET NAMES 'utf8'");

Вставил после открытия соединения с базой — и заработало! Я увидел список категорий в разделе загрузок!

Следующий сложный для меня этап: как произвести запись в строку таблицы mysql? Опять обращаюсь к гуглу. А что делать? Выхода нет — нужно смотреть как написать запрос к базе. Этот этап несколько сложнее, так как теперь я уже пытаюсь писать в базу данных. Одна неудачная команда и я испорчу базу. Придется ее восстановить из архива и делать новую попытку. В принципе, я обошелся всего двумя или тремя попытками. После этого у меня уже был вполне рабочий скрипт, который выполняет пункты 1) и 2) моего скромного ТЗ: переносит записи из таблицы jx25_docman_category в jx25_phocadownload_category и таблицы jx25_docman в jx25_phocadownload.

Привожу здесь полный текст этого скрипта:
<?php
echo "<!DOCTYPE html>";
echo "<html><head>";
echo "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />";
echo "</head><body>";

echo "Hello World! Привет!";

$con=mysqli_connect("localhost","user","password","database");

mysqli_query($con,"SET NAMES 'utf8'");
sql_mode='STRUCT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'");

// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

echo "Clear table jx25_phocadownload_categories";
mysqli_query($con,"DELETE FROM jx25_phocadownload_categories");

echo "Import table jx25_phocadownload_categories from jx25_docman_categories";
$result = mysqli_query($con,"SELECT * FROM jx25_docman_categories");

while($row = mysqli_fetch_array($result))
{
    $id = $row['id'];
    $parent_id = $row['parent_id'];
    $title = $row['title'];
    $name = $row['name'];
    $alias = $row['alias'];
    $descripton = $row['description'];
    $published = $row['published'];
    $ordering = $row['ordering'];
    $access = $row['access'];

    echo "<p>".$id."*".$parent_id."*".$title."*".$name."*".$alias."*".$description."*".$published."*".$ordering."*".$access."</p>";
    $sql = "INSERT INTO jx25_phocadownload_categories ( ".
		  " id,      parent_id,     title,     name,     alias,     description,     published,     ordering,     access ) " .
	"VALUES ( '".$id."','".$parent_id."','".$title."','".$name."','".$alias."','".$description."','".$published."','".$ordering."','".$access."')";
    //echo "<p>".$sql."</p>";
    mysqli_query($con,$sql);
}

echo "<p>***********************************</p>";

echo "Clear table jx25_phocadownload";
mysqli_query($con,"DELETE FROM jx25_phocadownload");

echo "Import table jx25_phocadownload from jx25_docman";
$result = mysqli_query($con,"SELECT * FROM jx25_docman");

while($row = mysqli_fetch_array($result))
{
    $id = $row['id'];
    $alias = "";
    $approved = 1;
    $catid = $row['catid'];
    $dmname = $row['dmname'];
    $dmdescription = $row['dmdescription'];
    $dmdate_published = $row['dmdate_published'];
    $dmfilename = $row['dmfilename'];
    $ext = pathinfo($dmfilename,PATHINFO_EXTENSION);
    $icon = "";
    if( strlen($ext)==3 )
	$icon = $ext.".png";
    $published = $row['published'];
    $dmcounter = $row['dmcounter'];
    $access = $row['access'];

    echo "<p>".$id."*".$dmfilename."</p>";
    $sql = "INSERT INTO jx25_phocadownload ( ".
		  " id,         catid,       title,        alias,       filename,         image_filename, description,         date,                   publish_up,             published,       approved,       hits,            access ) " .
	"VALUES ( '".$id."','".$catid."','".$dmname."','".$alias."','".$dmfilename."','".$icon."','"    .$dmdescription."','".$dmdate_published."','".$dmdate_published."','".$published."','".$approved."','".$dmcounter."','".$access."')";
    //echo "<p>".$sql."</p>";
    mysqli_query($con,$sql);
}

mysqli_close($con);

echo "</body>";
echo "</html>";
?>


Конечно, кроме манипуляций с базой нужно сделать еще кое что в файловой системе. Например, по умолчанию DOCman хранит файлы в папке ./dmdocuments, а phoca хранит их в ./phocadownload. Значит нужно еще переименовать папку, ну еще позаботиться об иконках файлов. Phoca ищет иконки в ./images/phocadownload и следовательно туда нужно положить иконки для разных типов файлов zip.png, pdf.png, txt.png и так далее…

Теперь нужно выполнить следующую задачу: разные статьи сайта имеют ссылки для скачивания с использованием компонента DOCman. Если я удалю DOCman то и все ссылки на скачивание по всем страницам сайта (которых у меня около трехсот) перестанут работать. Ссылки выглядят на сайте вот так:


А в тексте статьи это вот такой html код:
<a href="index.php?option=com_docman&task=doc_download&gid=181&Itemid=25" class="doclink"><img src="/components/com_docman/themes/default/images/icons/16x16/zip.png" alt="icon" border="0" /> Управление светодиодной лентой (<span class="small">79.68 Кбайт</span>)</a>

Код обычно вставляется в статью с помощью кнопки DOCLink.

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

Тут несколько сложностей. Во-первых, в статье может быть много ссылок на скачивание. Во-вторых ссылки на скачивание могут быть не только в теле статьи, но и в предварительном описании статьи, это то, что перед катом стоит, и еще ссылки могут быть даже в описаниях категорий. Кажется довольно опасным затрагивать столько статей, но выхода нет, нужно действовать.

Пожалуй не буду утомлять читателей всем списков моих запросов к гуглу. Такой метод программирования, когда чуть ли ни каждую строку кода приходится гуглить, ни в коей мере нельзя считать нормальным. Какое-то monkey-style программирование: мало понимания, но много попыток: попробовал => посмотрел работает ли.

Скажу, что в конце концов я смог сделать и второй скрипт, который модифицирует статьи сайта и заменяет док-линки на пфока-линки. Пожалуй единственная очень большая засада у меня получилась с вписыванием нового исправленного текста назад в запись таблицы. Честно скажу, тут потратил где-то пол дня на какую-то ерунду.

Все гугло-ответы, которые я находил показывали, что запрос нужно делать примерно вот так:
$sql="UPDATE Customers SET ContactName='Alfred Schmidt', City='Frankfurt' WHERE CustomerID=1;"

Этот пример взят отсюда: www.w3schools.com/sql/sql_update.asp

Однако, в моем случае такой запрос не работает! Я не могу таким способом исправлять поле, где хранится статья. Поле, где хранится текст статьи в таблице joomla называется fulltext, а это возможно/наверное/похоже на то — какое-то ключевое слово в mysql! Вот когда заключил имя поля в кавычки `fulltext` — все и заработало. И кто бы мог об этом подумать? И главное, что я не видел ни одного ссылки в гугле, которая бы про это рассказала. Понял я свою ошибку совершенно случайно, когда увидел, как запросы отображает phpmyadmin — уж там все имена полей в кавычках.

Вот мой скрипт, который просматривает все статьи и модифицирует ссылки на скачивание:
<?php
echo "<!DOCTYPE html>";
echo "<html><head>";
echo "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />";
echo "</head><body>";

echo "Hello World! Привет!";

$con=mysqli_connect("localhost","user","password","database");

mysqli_query($con,"SET NAMES 'utf8'");

// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

function search_replace($text)
{
    $pos = strpos( $text, "task=doc_download");
    if($pos===false)
    {
	return "";
    }
    else
    {
	$begin = $pos;
	while($begin>=0)
	{
	    $ss = substr($text,$begin,3);
	    if($ss=="<a ") break;
		$begin--;
	}
	$end = $pos;
	while(1)
	{
	    $ss = substr($text,$end,4);
	    if($ss=="</a>") { $end=$end+4; break; }
		$end++;
	}

	$ss = substr($text,$begin,$end-$begin);
	echo "<p>".$ss."</p>";

	$gid_pos = strpos($ss,"gid=");
	$gid = substr($ss,$gid_pos+4);
	$gid_int = intval($gid);
	$phoca_str = "{phocadownload view=file|id=".$gid_int."}";
	echo "<p>".$phoca_str."</p>";

	$a = substr($text,0,$begin);
	$b = substr($text,$end);
	return $a.$phoca_str.$b;
    }
}

echo "Read table jx25_content";
$result = mysqli_query($con,"SELECT * FROM jx25_content");
$num=0;
while($row = mysqli_fetch_array($result))
{
    $id = $row['id'];
    $title = $row['title'];
    $fulltext = $row['fulltext'];
    $introtext = $row['introtext'];
    $num=$num+1;
    echo "<p><hr>".$num." ".$id." ".$title."</p>";
    $text = $fulltext;
    while( strlen($text)>0 )
    {
	$t = search_replace($text);
	if( strlen($t)==0 ) break;
	$text=$t;
    }
    if($text!=$fulltext)
    {
	$str = mysqli_real_escape_string($con,$text);
	echo "*** strlen ".intval(strlen($str));
	$sid = intval($id);
	$sql = "UPDATE jx25_content SET `fulltext`='".$str."' WHERE id=".$sid;
	$r = mysqli_query($con,$sql);
	if($r) echo "***";
	else echo "---";
    }
}

echo "<p>***********************************</p>";

?>


Теперь PhocaDownload ссылки на сайте у меня выглядят вот так:


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

Таким образом:
  • потрачено четыре вечера;
  • получен бесценный опыт программирования на незнакомом языке;
  • есть результат: смог самостоятельно мигрировать с DOCman на PhocaDownload!

комментарии (3)

+1
wOvAN ,  
Мне кажется, это обычное дело писать программы на языке и в процессе его изучать. Первый результат будет долгим и комом, но второй уже будет лучше и тд.
+2
samodum ,   * (был изменён)
MySql — это СУБД. А язык — это SQL.
0
+1 –1
hacklex ,  
Всё хорошо. Далеко идущие выводы из этого делать сложно, так как у php весьма низкий порог вхождения.