MySQL Использование Count в LEFT JOIN

До сегодняшнего дня ни раза не использовал LEFT JOIN и COUNT вместе в одном запросе. Проходя собеседование в одной компании мне предложили написать подобное решение. Сразу сделать его прямо на собеседовании я не смог, по этому решил почитать документацию и все проверить в свободное время.

Для примера давайте возьмем 2 таблицы. Первая будет таблица пользователей, а вторая ихних сайтов.

Таблица пользователей:

--
-- Структура таблицы `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- Дамп данных таблицы `users`
--

INSERT INTO `users` (`id`, `username`) VALUES
(1, 'test1'),
(2, 'test2');

Таблица сайтов:

--
-- Структура таблицы `sites`
--

CREATE TABLE IF NOT EXISTS `sites` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `domain` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `user_id_2` (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- Дамп данных таблицы `sites`
--

INSERT INTO `sites` (`id`, `user_id`, `domain`) VALUES
(1, 1, 'test1.com'),
(2, 1, 'test2.com'),
(3, 2, 'test3.com');

--
-- Ограничения внешнего ключа таблицы `sites`
--
ALTER TABLE `sites`
  ADD CONSTRAINT `sites_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
  ON DELETE CASCADE ON UPDATE CASCADE;

Форматирование JavaScript и JSON в консоли Linux

ExtJS Tree PanelДля того что бы форматировать JavaScript код существует множество сервисов и один из самых популярных http://jsbeautifier.org. Мне довольно часто доводилось пользоваться им для форматирования json или обфусцированного JavaScript кода. Сервис хорош всем, кроме одного, когда я пытаюсь форматировать файл большого размера (Более 2 мб) браузеры начинают жутко тормозить при попытке добавить такой объем данных в textarea.

Зайдя на сайт Online JavaScript beautifier и посмотрев через firebug ихние скрипты вы можете увидеть что они использует файл beautify.js, который к тому же распространяется под лицензией MIT, которая позволяет его использовать, изменять и передавать третьим лицам. При этом она допускает его использование коммерческих проектах тоже.

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

greed@laptop:~/bin$ wget http://jsbeautifier.org/js/lib/beautify.js

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

    } else if (typeof exports !== "undefined") {
        // Add support for CommonJS. Just put this file somewhere on your require.paths
        // and you will be able to `var js_beautify = require("beautify").js_beautify`.
        exports.js_beautify = js_beautify;
    }

NodeJS Ошибки в NPM и установка из исходников

Работая над второй частью статьи по NodeJS столкнулся с проблемой работы NPM из стандартного репозитория пакетов в Ubuntu. В целом все работало нормально, установка, удаление и просмотр информации о пакетах, но при любой попытки поиска пакета я получал в консоль следующею ошибку:

greed@laptop:~$ npm search mysql
npm http GET https://registry.npmjs.org/-/all/since?stale=update_after&startkey=1396395215219
npm http 200 https://registry.npmjs.org/-/all/since?stale=update_after&startkey=1396395215219
npm ERR! TypeError: Object.keys called on non-object
npm ERR!     at Function.keys (native)
npm ERR!     at stripData (/usr/share/npm/lib/search.js:89:28)
npm ERR!     at Array.map (native)
npm ERR!     at filter (/usr/share/npm/lib/search.js:73:6)
npm ERR!     at /usr/share/npm/lib/search.js:63:21
npm ERR!     at /usr/share/npm/node_modules/npm-registry-client/lib/get.js:89:14
npm ERR!     at /usr/lib/nodejs/graceful-fs/graceful-fs.js:103:5
npm ERR!     at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     
npm ERR! or use
npm ERR!     reportbug --attach /home/greed/npm-debug.log npm

npm ERR! System Linux 3.11.0-19-generic
npm ERR! command "/usr/bin/nodejs" "/usr/bin/npm" "search" "mysql"
npm ERR! cwd /home/greed
npm ERR! node -v v0.10.15
npm ERR! npm -v 1.2.18
npm ERR! type called_on_non_object
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /home/greed/npm-debug.log
npm ERR! not ok code 0
greed@laptop:~$ 

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

sudo apt-get install python g++ make checkinstall git

NodeJS получение Post JSON

ExtJS Tree PanelВ качестве небольшого дополнения к статьям Curl Post JSON и NodeJS Установка и использование решил написать от том как получать Post JSON в NodeJS. За основу возьмем http-сервер который мы уже создавали в статье NodeJS установка и использование. Я приведу сразу готовый класс сервера на основе, который будет принимать post JSON:

var http = require('http');
var port = 1337;
var host = '127.0.0.1';

http.createServer(function(request, response) {
    console.log('From: '+request.connection.remoteAddress+', Path: '+request.url);

    if(request.method === 'POST'){
        var text = '';
        request.addListener('data', function(chunk) {
            text += chunk;
        });
        
        request.addListener('end', function() {
            if(text){
                try {
                    var jsonObject = JSON.parse(text);
                    response.writeHeader(200, {
                        'Content-Type': 'application/json'
                    });
                    response.end(JSON.stringify({
                        success: true,
                        username: jsonObject.username
                    }));
                } catch(e) {
                    response.writeHead(500, {
                        'content-type': 'text/plain'
                    });
                    response.end('Post json data cannot be parsed: '+e);
                }
            } else {
                response.writeHeader(200, {
                    'Content-Type': 'text/html'
                });
                response.end('No Data Provided!');
            }
        });
    } else {
        response.writeHeader(200, {
            'Content-Type': 'text/html'
        });
        response.end('No Data Provided!');
    }
}).listen(port, host);

console.log('Server start at http://'+host+':'+port+'/');

PHP - Curl Post JSON

Довольно часто мне приходилось передавать данные на сервер в различными способами таких как GET или POST, но существует еще один удобный способ передачи данных на сервер это Post JSON. Его удобно использовать в тех случаях когда мы передаем сложные структуры данных. Давайте представим с вами ситуацию когда мы хотим передать на сервер объект/массив(данные пользователя) и сопутствующие к нему связи. На пример мы хотим отправить Пользователя, его статьи и комментарии для этих статей. 

Для примера мы можем использовать ассоциативный массив следующего вида:

<?php
$user = array(
    'id' => 1,
    'username' => 'jon123',
    'first_name' => 'Jon',
    'last_name' => 'Dou',
    'articles' => array(
        array(
            'id'=>1,
            'title' => 'My First Page',
            'content' => '<h1>Hello it my first page</h1>',
            'comments' => array(
                array(
                    'id'=>1,
                    'username' => 'Jack',
                    'text' => 'Hey it is a great blog!'
                ),
                array(
                    'id'=>2,
                    'username' => 'Nick',
                    'text' => '+100500!'
                )
            )
        ),
        array(
            'id'=>2,
            'title' => 'Free time',
            'content' => 'Do you have any free time?',
            'comments' => array(
                array(
                    'id'=>3,
                    'username' => 'Nick',
                    'text' => 'Free time? You are joking?'
                )
            )
        )
    )
);

Зачем нам передавать его через Post JSON, если его можно передать через обычный POST-запрос? Одна из причин это удобство работы с форматом JSON. нам не придется придется преобразовывать имена параметров в запрос приводя их к виду article[1][commet][1][name] = 'Hey it is a great blog!' для того что бы получить такой же массив при получении данных на сервере, другая заключается в том, что если принимающей стороной будет не PHP, а к примеру NodeJS работать с полученными данными будет намного удобней. Также стоит отметит что количество передаваемых данных будет немного ниже чем при обычном POST запросе.

Част 1. NodeJS Установка и использование

ExtJS Tree PanelNodeJS - серверная реализация JavaScript получившая в последние время большое распространение. Многие крупные интернет-сервисы такие Amazon, ВКонтакте используют его для снижения нагрузки на своих серверах. Главным критерием для выбора NodeJS обычно является скорость его работы, простота в написании кода и низкое потребление памяти по сравнению с такими гигантами, как Java или Ruby. В этой статье я хочу рассказать, о том как нам установить NodeJS и подготовить его к работе. Мы также напишем несколько простых приложений которые на помогут с ним разобраться.

Установка

Для дальнейшей работы NodeJS на нужно установить 2 пакета, один это сам nodejs и второй npm (Node Package Manager)- пакетный менеджер для NodeJS, который нам даст возможность быстро и удобно устанавливать библиотеки и фреймворки для nodejs. В ubuntu 13.10 для установки этих двух пакетов на необходимо выполнить команду:

sudo apt-get install nodejs npm

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

greed@laptop:~$ npm -v
1.2.18
greed@laptop:~$ nodejs -v
v0.10.15
greed@laptop:~$ 

PHP - Преобразование XML to Array

Для работы с xml в php, есть удобное расширение SimpleXML, которое помогает вам производить манипуляции с DOM. К недостаткам стоит отнести неудобства по работе с объектом который мы получаем и в результате работы simplexml_load_string. Совсем другое дело обстоит с json, нам все навсего нужно использовать метод json_encode, чтобы получить из него объект или массив. Здесь будет показано каким образом получать массив из xml.

После небольшого поиска в интернете, мне удалось найти два решения, которые соответствовали всем необходимым мне требованиям. Для проверки работы кода будет использован следующий XML:

<?xml version="1.0" ?>
<states>
    <state id="AL">     
     <name>Alabama</name>
    </state>
    <state id="AK">
        <name>Alaska</name>
    </state>
</states>

Как оказалось самый простой способ - это преобразовать объект XML в json строку и затем преобразовать обратно в объект/массив:

<?php
function xml2array($text, $is_array = true) {
    $xml = simplexml_load_string($text);
    $json = json_encode($xml);
    return json_decode($json, $is_array);
}
?>

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

Array
(
    [state] => Array
        (
            [0] => Array
                (
                    [@attributes] => Array
                        (
                            [id] => AL
                        )

                    [name] => Alabama
                )

            [1] => Array
                (
                    [@attributes] => Array
                        (
                            [id] => AK
                        )

                    [name] => Alaska
                )

        )

)

PHP - GeoIP Модуль

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

Установка GeoIP

Для того что бы использовать этот модуль для начала его нужно установить. Я использую Ubuntu 13.10 по этому установка и настройка приведена именно для этой системы:

sudo apt-get install php5-geoip

Для того что бы получать актуальные данные вам необходимо скачать последнюю базу GeoIP. Сделать вы этому можете по этому адресу http://dev.maxmind.com/geoip/legacy/geolite/. После того как вы скачали последнюю базу ее необходимо распаковать. У вас должно быть 2 файла GeoIP.dat и GeoLiteCity.dat (его нужно переименовать в GeoIPCity.dat), которые нужно скопировать в директорию /usr/share/GeoIP. После этого приготовления к использованию завершены и мы можем проверить работу этот модуля.

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

<?php  
$data = geoip_record_by_name('8.8.8.8');
print_r($data);
?>

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

Array
(
    [continent_code] => NA
    [country_code] => US
    [country_code3] => USA
    [country_name] => United States
    [region] => CA
    [city] => San Francisco
    [postal_code] => 94107
    [latitude] => 37.76969909668
    [longitude] => -122.39330291748
    [dma_code] => 807
    [area_code] => 415
)

Сортировка массива в JavaScript

Недавно ко мне подошел один мой знакомы, программист с опытом в 3 года в frontend-разработке и попросил помочь объяснить почему функция sort в javascript работает неправильно. Был массив из цифр [1, 2, 15, 3] и при вызове метода sort результатом сортировки должен быть массив [1, 2, 3, 15], а не результат который он получал [1, 15, 2, 3]. Я был немного удивлен т.к. для меня это было очевидно. Пообщавшись еще с несколькими программистами я понял, что понимание каким именно образом работают сортировка массивов в javascript есть далеко не у всех. Здесь я постараюсь рассказать как работает сортировка массива sort и какие подводные камни нас ждут.

Для начала что бы понять как работает sort в javascript возьмем два массива:

  1. [1, 2, 15, 3] - массив значений типа Integer.
  2. ['1', '2', '15', '3'] - массив значений типа String.

Если мы попытаемся сортировать оба этих массива мы получим [1, 15, 2, 3] и ['1', '15, '2', '3'] соответственно для обоих случаев. С точки зрения сортировки строк мы получаем правильное значение т.к. тут идет посимвольная сортировка. Число(строка) '15' разбивается на две части на 1 и на 5. В начале идет сравнение первого числа с элементами массива. 1 < 2 и будет поднято в вверх на одну позицию. При сравнении с 1 и 1 они будут равны и и по этому сортировка будет для них происходить по второму числу у '1' его нет а у '15' это 5 и пустое значение меньше 5. В результате мы получим что '15' попадает на второе место.

Alternative PHP Cache

Alternative PHP Cache или просто APC - является модулем PECL для php, который позволяет нам кешировать байт-код наших скриптов, который получается после интерпретации исходных фалов  и тем самым ускоряет ихнею работу. Помимо APC также существуют и другие модули которые позволяют кешировать байт-код php скриптов. К ним относятся eAccelerator, PhpExpress, XCache и Zend OPcache(Включен в php начиная с версии 5.5).

Стоит отметить, что APC позволяет хранить данные в виде хеш-таблиц, также как это позволяет делать memcahce.

Как работает APC?

Для того что бы понять каким образом APC укоряет работу php давайте рассмотрим как происходит обычная обработка php файла. Весь процесс от простого файла который лежит в файловой системе и до того момента как получаем результат его работы со стороны интерпретатора php выглядит следующим образом:

  1. Чтение файла из файловой системы.
  2. Компиляция полученного кода в байт-код.
  3. Выполнение полученного байт-кода.
  4. Результат - ответ  от сервера или отображение результата в консоль.(Этот шаг может быть частью 3 шага - выполнение)

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