,

19 октября, 2024

Пишем крестики нолики на javascript :)

Ради развлечения решил вспомнить немного JS и вот что в итоге получилось! Простая игра на Javascript — крестики нолики

Вот шаблон html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <link rel="stylesheet" href="x0.css">
    <script src="x0.js"></script>
</head>
<body>
<div class="status"></div>
<div class="gamespace"></div>
</body>
</html>

Код стилей x0.css

.gamespace .row * {
    box-sizing: border-box;
}
.gamespace .row {
    display: flex;
    flex-wrap: wrap;
}
.gamespace .col {
    width: 33%;
    position: relative;
    overflow: hidden;
    border: 3px solid #000;
}
.gamespace .col:after {
    content: "";
    padding-top: 100%;
    float: left;
}
.gamespace .item {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    flex-flow: column;
    align-items: center;
    justify-content: center;
    color: #000;
    font-size: 8em;
}
.gamespace {
    width: 30%;
    margin: 0 auto;
}
.status {
    text-align: center;
    font-size: 2em;
}

И собственно сама бизнес логика приложения

window.addEventListener('load', function () {
    window.game = {
        finishGame: false,
        cells: 3,
        players: {
            zero: {
                value: 0,
                symbol: '0',
            },
            crosse: {
                value: 1,
                symbol: 'X',
            }
        },
        activePlayer: null,
        result: [
            [null, null, null],
            [null, null, null],
            [null, null, null]
        ],
        init: function() {
            this.activePlayer = this.players.crosse;
            this.createGameSpace();
            document.querySelector('.status').innerHTML = 'Ходит игрок: ' + this.activePlayer.symbol;
        },
        createGameSpace: function() {
            let gamespace = '';
            for(let i = 0; i < this.cells; i++) {
                gamespace += this.createRow(i);
            }
            document.querySelector('.gamespace').innerHTML = gamespace;
        },
        createRow: function(i) {
            let row = document.createElement('div');
            row.classList.add('row');
            for(let j =0; j < this.cells; j++) {
                let col = document.createElement('div');
                col.classList.add('col');
                col.insertAdjacentHTML('beforeend', this.createItem(i, j));
                row.insertAdjacentHTML('beforeend', col.outerHTML);
            }

            return row.outerHTML;
        },
        createItem: function(i, j) {
            let item = document.createElement('div');
            item.classList.add('item');
            item.dataset.row = i;
            item.dataset.col = j;

            return item.outerHTML;
        },
        switchPlayer: function() {
            this.activePlayer = this.activePlayer === this.players.zero ? this.players.crosse : this.players.zero;
        },
        finish: function() {
            this.finishGame = true;
        },
        checkWin: function() {
            let isWin = false;
            loop: for (let i = 0; i < this.result.length; i++) {
                for(let j =0; j < this.result[i].length; j++) {
                    if(this.winRow(i,j) || this.winCol(i,j)) {
                        isWin = true;
                        break loop;
                    }
                }
            }
            return isWin || this.winDia();
        },
        winRow: function(row,col) {
            return null !== this.result[row][col] && this.result[row][col] === this.result[row][col+1] && this.result[row][col] === this.result[row][col+2];
        },
        winCol: function(row,col) {
            return null !== this.result[row][col] && this.result[row][col] === this.result[row+1][col] && this.result[row][col] === this.result[row+2][col];
        },
        winDia: function() {
            return this.winDia1() || this.winDia2();
        },
        winDia1: function() {
            return this.result[0][0] === this.result[1][1] && this.result[0][0]  === this.result[2][2] && null !== this.result[0][0]
        },
        winDia2: function() {
            return this.result[0][2] === this.result[1][1] && this.result[0][2] === this.result[2][0] && null !== this.result[0][2];
        },
        showWinLine: function(isWin) {
            if (this.finishGame) {
                window.game.switchPlayer();
                document.querySelector('.status').innerHTML = 'Победил: ' + this.activePlayer.symbol;
            } else {
                document.querySelector('.status').innerHTML = this.isStandoff() ? 'Ничья!' : 'Ходит игрок: ' + this.activePlayer.symbol;
            }
        },
        isStandoff: function() {
            let standoff = true;
            for(let i = 0; i < this.result.length; i++) {
                for(let j = 0; j < this.result[i].length; j++) {
                    if (null === this.result[i][j]) {
                        standoff = false;
                    }
                }
            }
            return standoff;
        }
    }
    window.game.init();
    document.querySelectorAll('.item').forEach(function (e) {
        e.addEventListener('click', function () {
            if ('' === e.innerText && !window.game.finishGame) {
                e.innerText = window.game.activePlayer.symbol;
                window.game.result[parseInt(e.dataset.row)][parseInt(e.dataset.col)] = window.game.activePlayer.value;
                window.game.switchPlayer();
                window.game.showWinLine();
                let finishGame = window.game.checkWin();
                if (finishGame) {
                    window.game.finish();
                    window.game.showWinLine();
                }
            }
        });
    });
});

Код игры можно скачать отсюда — https://github.com/wikide/x0.git

,

6 октября, 2024

Создаем систему для партнерских программ в WordPress

Всем привет! В рамках реализации задачи по монетизации блога на wordpress мне пришла в голову мысль добавить партнерских программ на свой сайт, пертнерок тех компаний услагами которых я пользуюсь самостоятельно, но для реализации этой задачи нужно немного допилить wordpress, от сторонних плагинов по традиции решил отказаться потому что не хочу =) и к тому же для реализации такой простой задачи достаточно будет возможностей wordpress. Итак, поехали. Далее я опишу процесс создания системы партнерских программ для блога.

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

Открываем functions.php темы и добавляем туда что-то вроде:

add_action('init', 'register_post_types');

function register_post_types()
{
    register_post_type('partner', [
        'label' => null,
        'labels' => [
            'name' => 'Партнерки',
            'singular_name' => 'partner',
            'add_new' => 'Добавить партнерку',
            'add_new_item' => 'Добавление партнерки',
            'edit_item' => 'Редактирование пертнерки',
            'new_item' => 'Новая партнерка',
            'view_item' => 'Смотреть партнерку',
            'search_items' => 'Искать патнерку',
            'not_found' => 'Не найдено',
            'not_found_in_trash' => 'Не найдено в корзине',
            'parent_item_colon' => '',
            'menu_name' => 'Партнерка',
        ],
        'description' => '',
        'public' => true,
        'show_in_menu' => null,
        'show_in_rest' => null,
        'rest_base' => null,
        'menu_position' => null,
        'menu_icon' => null,
        'hierarchical' => false,
        'supports' => ['title', 'thumbnail'], // 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats'
        'taxonomies' => [],
        'has_archive' => false,
        'rewrite' => true,
        'query_var' => true,
    ]);
}

После сохранения в админке WP должен появится новый пункт ниже пунтка меню Записи с названием Партнерки. Теперь у нас есть новый зарегистрированный тип записей с минимальным набором полей ( название и изображение ) для добавления наших партнеров.

Но по-мимо изображения и название так же требуется добавления реферальной ссылки, для этого потребуется для нового типа с партнерами зарегистрировать кастомезированые поля записей, поэтому добавляем следующий код в functions.php

add_action('add_meta_boxes', 'my_extra_fields_meta_box', 1);

function my_extra_fields_meta_box()
{
    $post_type = 'partner';
    add_meta_box('extra_fields', 'Дополнительные поля', 'extra_fields_box_func', $post_type, 'normal', 'high');
}

function extra_fields_box_func($post)
{
    ?>
    <p>
        Ссылка:
        <label>
            <input style="width: 100%;" type="text" name="extra[link]"
                   value="<?= get_post_meta($post->ID, 'link', 1) ?>"/>
        </label>
    </p>
    <p>
        Комментарий:
        <textarea type="text" name="extra[description]"
                  style="width:100%; height:50px;"><?= get_post_meta($post->ID, 'description', 1) ?></textarea>
    </p>
    <p>
        Количество переходов:
        <input type="text" name="extra[count]" value="<?= get_post_meta($post->ID, 'count', 1) ?>" disabled="disabled">
    </p>
    <input type="hidden" name="extra_fields_nonce" value="<?= wp_create_nonce('extra_fields_nonce_id') ?>"/>
    <?php
}

Я решил для своей системы добавить еще 2 свойства партнера, комментарий — для внутреннего использования и подсчета количества переходов по моей реферальной ссылке.

Для того чтобы дополнительные поля сохранялись так же требуется добавить следующий хук

add_action('save_post', 'my_extra_fields_save_on_update', 0);

function my_extra_fields_save_on_update($post_id)
{
    // базовая проверка
    if (
        empty($_POST['extra'])
        || !wp_verify_nonce($_POST['extra_fields_nonce'], 'extra_fields_nonce_id')
        || wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)
    ) {
        return false;
    }

    $extra = $_POST['extra'];

    // Все ОК! Теперь, нужно сохранить/удалить данные

    // Очищаем все данные
    $extra = array_map('sanitize_text_field', $extra);
    foreach ($extra as $key => $value) {
        // удаляем поле если значение пустое
        if (!$value) {
            delete_post_meta($post_id, $key);
        } else {
            update_post_meta($post_id, $key, $value); // add_post_meta() работает автоматически
        }
    }

    return $post_id;
}

Админка готова! Теперь необходимо доработать шаблоны темы, чтобы партнерские программ начали выводится на сайт.

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

function get_partner_random() {
    $query = new WP_Query([]);
    $query->query([
        'post_type' => 'partner',
        'post_status' => 'publish',
        'orderby' => 'rand',
        'posts_per_page' => '1'
    ]);

    return $query->posts[0] ?? null;
}

Так как я хочу увеличивать количество переходов на 1 каждый раз при переходе по моей реферальной ссылки требуется добавить функцию проксирования партнерских ссылок. Это можно сделать довольно просто добавив следующий хук в functions.php

add_action( 'init', 'init_proxy' );

function init_proxy() {
    if (
            isset($_GET['action']) &&
            $_GET['action'] == 'partner' &&
            isset($_GET['id']) &&
            is_numeric($_GET['id'])
    ) {
        $query = new WP_Query([]);
        $query->query([
            'post_type' => 'partner',
            'ID' => (int)$_GET['id'],
            'post_status' => 'publish',
            'posts_per_page' => '1'
        ]);
        $posts = $query->get_posts();
        if (!empty($posts[0]->ID)) {
            $count = (int)get_post_meta($posts[0]->ID, 'count', true);
            $count++;
            update_post_meta($posts[0]->ID, 'count', $count);
            header('Location: ' . get_post_meta($posts[0]->ID, 'link', true));
            exit;
        }
    }
}

Теперь уже точно можно перейти к шаблону сайта. Тут все зависит от сложности шаблона. В моем случае шаблон очень простой поэтому править потребуется не так много

Добавляем новый шаблон для партнерок:

<?php
/** @var WP_Post $partner */
$partner = get_partner_random();
?>
<?php if ($partner): ?>
<article>
    <header class="entry-header">
        <header class="entry-header">
            <h2 class="entry-title"><a href="<?php echo sprintf('/?action=partner&id=%d', $partner->ID) ?>" rel="bookmark"><?php echo $partner->post_title?></a></h2>
        </header>
        <div class="post-thumbnail">
                <a href="<?php echo sprintf('/?action=partner&id=%d', $partner->ID) ?>">
                    <?php echo get_the_post_thumbnail( $partner->ID, 'large'); ?>
                </a>
        </div><!-- .post-thumbnail -->
        <div class="nav-links">
            <div class="nav-next kc-nav-links">
                <a href="<?php echo sprintf('/?action=partner&id=%d', $partner->ID) ?>">Взглянуть →</a>
            </div>
        </div>
    </header>
</article>
<?php endif ?>

И далее добавляем логику вывода этого шаблона в index.php темы

get_template_part( 'header' );

				if ( have_posts() ) :

                    $i = 1;
					while ( have_posts() ) :

						the_post();

						get_template_part( 'content' );

						// If comments are open or we have at least one comment, load up the comment template.
						if ( comments_open() || get_comments_number() ) :
							comments_template();
						endif;

                        if ($i % 5 == 0) {
                            get_template_part( 'partner' );
                        }

                    $i++;
					endwhile;

				else :

					get_template_part( 'content', 'none' );

				endif;
				?>

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

                        if ($i % 5 == 0) {
                            get_template_part( 'partner' );
                        }

Этот код будет отображать рандомную партнерку после каждых 5 постов

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

А если вам нужна разработка под WP или любая другая помощь по php, можете написать мне в любое время в мой телеграмм на странице профайла

,

4 августа, 2024

Автопубликация постов WordPress в Telegram

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

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

Итак, для репоста в свой телеграм канал, нам потребуется сайт на WordPress, телеграм канал и токен бота, который потребуется получить через папу ботов телеграмма — @BotFather

Открываем @BotFather пишим ему команду

/newbot

В ответ от вас потребуется придумать и ввести имя бота и имя бота с постфексом _bot
После этого папа ботов сгенерирует для вас токен для HTTP API

Этот токен мы и будем использовать для нашей системы репостинга обновлений на сайте

после этого требуется отредактировать wp-config.php и добавить туда константу:

define( 'TELEGRAM_BOT_TOKEN', '<TOKEN>' );

<TOKEN> заменить на тот токен, который мы получили при создании нового бота через @BotFather

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

  1. Добавляем в качестве администратора нашего новорожденного бота на наш канал
  2. Публикуем тестовый пост ( который потом будет не жалко удалить )
  3. Выполняем элементарный запрос curl
    curl —location ‘https://api.telegram.org/bot<TOKEN>/getUpdates’
  4. В ответ получаем ID нашего чата, который вставляем в wp-config.php
define( 'TELEGRAM_CHANNEL_ID',  <ID_CHANNEL> );

Теперь все готово к написанию нашего основного функционала!

Открываем нашу текущую тему WordPress ( предварительно скопировав ее в новую директорию, чтобы обновления темы не затерли наши изменения ) и находим там файл functions.php, в него мы и будем вносить изменения.

В данном случае нас интересуют только новые посты, поэтому мы будем использовать событие WordPress — save_post

Регистрируем новую функцию, которая будет выполнятся каждый раз, когда на сайте будет опубликован новый пост

add_action( 'save_post', 'send_telegram' );

Теперь, напишем код функции send_telegram

function send_telegram( $post_id ) {
    $post = get_post($post_id);
    $is_new = $post->post_date === $post->post_modified;
    if (  !$is_new || wp_is_post_revision( $post_id ) || $post->post_status != 'publish')
        return;
    message_to_telegram( $post );
}

Эта функция выполняет проверяет является ли пост новым публичным и не ревизией поста и если эти условия выполняются, то вызывается функция message_to_telegram

function message_to_telegram($post)
{
    $url = get_permalink($post->ID);
    $text = preg_replace('/[\n\r]+/s', "\n\n", strip_tags($post->post_content));
    if (strlen($text) > 500) {
        $text = substr($text, 0, 500) . '...';
    }
    $ch = curl_init();
    $ch_post = [
        CURLOPT_URL => sprintf('https://api.telegram.org/bot%s/sendMessage', TELEGRAM_BOT_TOKEN),
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_POSTFIELDS => [
            'chat_id' => TELEGRAM_CHANNEL_ID,
            'parse_mode' => 'HTML',
            'text' => sprintf("<a href=\"%s\">%s</a> %s \n\n<a href=\"%s\">Взглянуть ?</a>", $url, $post->post_title, $text, $url),
        ]
    ];

    curl_setopt_array($ch, $ch_post);
    curl_exec($ch);
}

Эта функция выполняет отправку ссылку и первые 500 символов нового поста в канал телеграм

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

А если вас интересует создание ботов телеграм или создание сайта на движке wordpress то всегда можете написать мне в телеграм.

Docker + Wordpress

, ,

31 июля, 2024

Поднимаем локально докер для WordPress

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

Когда-то давно еще во допотоные времена до ядерной войны в 18 веке лет 5 назад мы делали это при помощи вирутальной машины, которая работала через vagrant или вообще разворачивали всю экосистему локально, но сейчас времена наступили другие и появилась докеризация

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

Тут же я хотел продемонстрировать простое решение на докере, которое позволяет развернуть локально такой простой блок на WordPress как этот блог. Итак поехали.

Для начала создаем файл .env с таким содержимым

# префикс, который мы будем использовать для наименования контейнеров в докере
PREFIX=wp

# пароль root для локального контейнера с mysql
MYSQL_ROOT_PASSWORD=somewordpress

# название базы данных root для локального контейнера с mysql
MYSQL_DATABASE=wordpress

# имя пользователя базы данных для локального контейнера с mysql
MYSQL_USER=wordpress

# пароль пользователя базы данных для локального контейнера с mysql
MYSQL_PASSWORD=wordpress

# хоста базы данных на боевом сервере
MYSQL_REMOTE_HOST=remote_host_address

# название базы данных на боевом сервере
MYSQL_REMOTE_DATABASE=remote_wp

# имя пользователя базы данных на боевом сервере
MYSQL_REMOTE_USER=user_db_read

# пароль пользователя базы данных на боевом сервере
MYSQL_REMOTE_PASSWORD=password_db_read

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

Далее создаем docker-compose.yml

services:
  db:
    container_name: ${PREFIX}-db
    # We use a mariadb image which supports both amd64 & arm64 architecture
    image: mariadb:10.6.4-focal
    # If you really want to use MySQL, uncomment the following line
    #image: mysql:8.0.27
    command: '--default-authentication-plugin=mysql_native_password'
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    expose:
      - 3306
      - 33060
    ports:
      - 3306:3306
      - 33060:33060
  wordpress:
    container_name: ${PREFIX}-wp
    image: wordpress:latest
    volumes:
      - ./www:/var/www/html
    ports:
      - 8082:80
    restart: always
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=${MYSQL_DATABASE}
      - WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD}
      - WORDPRESS_DB_NAME=${MYSQL_DATABASE}
      - WORDPRESS_DEBUG=false
volumes:
  db_data:

Это основной файл нашей докер системы при использовании которого будет запущено 2 контейнера, контейнер с базой данных mysql и контейнер с образом wordpress

Все настройки перечислять не буду ( почитаете документацию если будет кому нужно ) отмечу только то что в ports: мы биндим порты на локальную машину http будет доступен на порте 8082, а mysql на порту 3306 так же хочу отметить еще что в секции valumes: контейнера wordpress мы биндим локальную директорию ./www в которой будут хранится файлы wordpress. В нее нужно будет развенуть архив с wordpress или скопировать файлы wordpress с удаленного хостинга.

В итоге у нас получается вот такая директория проекта с файлом .env, docker-compose.yml и директорией www с файлами wordpress, если не хотите прописывать данные доступов к базе данных вручную, то перед запуском сборки докера удалите файл wp-config.php. Контейнер wordpress создаст его вручную и пропишет в него доступы из docker-compose.yml

Далее запускаем вот такую простую команду

$ docker compose up -d

Наслаждаемся процессом скачки образов и сборки контейнеров

Если вам повезло, то после этого можете зайти по адресу http://localhost:8082 откроется ваш wordpress

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

Итак, чтобы автоматзировать рутинные задачи создадим Makefile.

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

include .env
export
.DEFAULT_GOAL = help
.PHONY: help

help:
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

up:
	@docker compose up -d

build:
	@docker compose up --build -d

down:
	@docker stop `docker ps -a -q`

shell:
	@docker exec -it $(PREFIX)-wp bash

drop-db:
	@docker exec -it $(PREFIX)-db mysql -e 'DROP DATABASE $(MYSQL_DATABASE) ; CREATE DATABASE $(MYSQL_DATABASE)' -uroot -p$(MYSQL_ROOT_PASSWORD)

sync: drop-db
	@ssh $(MYSQL_REMOTE_HOST) mysqldump -u$(MYSQL_REMOTE_USER) -p$(MYSQL_REMOTE_PASSWORD) $(MYSQL_REMOTE_DATABASE) | docker exec -i $(PREFIX)-db mysql -u$(MYSQL_USER) -p$(MYSQL_PASSWORD) $(MYSQL_DATABASE)

После этого чтобы запустить наш докер с wordpress достаточно будет ввести команду

$ make up

Для того чтобы пересобрать контейнеры

$ make down

Остановить докер

$ make down

И самая интересная команд, команда синхронизации базы данных докера с базой данных боевого сервера

$ make sync

Она удаляет полностью базу данных в докере и полностью забирает ее с боевого хостинга, после этой операции у вас в контейнере базы данных будет полная копия базы боевого сайта с wordpress

В целом это все. Если вдруг возникнут какие-то вопросы и замечания, то можете писать в комменатрии или мне в телеграм, так же если кому-то требуется разработка сайта на wordpress пишите сюда :)

,

29 июля, 2024

Запиливаем удобный блок донатов в WordPress

Итак, решил реанимировать свой сайт и заодно подправить страницу профайл и добавил туда блок помощи, кстати, если есть возможность, то можете воспользоваться этой возможностью и поддержать меня.

Сначала добавил обычный текстовый блок, но вряд ли кто-то станет выделять и копировать текст для того чтобы отправить куда-то деньги, тогда я захотел немного упросить процесс и решил подключить javascript для решения этой задачи. От поиска готового решения для WP отказался так как для такой ерунды это не целесообразно, а всевозможные расширения и специальные плагины еще и слишком ресурсоемкие, к тому же я вспомнил что Я Ж программист и решил самостоятельно на коленки сделать свое решение. Как по мне так получилось достаточно неплохо, результат можете посмотреть тут ( а заодно и воспользоваться функционалом =) )

Итак, вот код:

Добавляем в стили шаблона css

.term {
	cursor: pointer;
	color: #2f8eff;
	text-decoration: none;
	border-bottom: 1px dashed #2f8eff;
}
.term:after {
	padding-left: 3px;
	content: url('/uploads/donate/copy.svg');
	display: inline-block;
	width: 20px;
	height: 20px;
}
.tooltiped {
	position: relative;
}
.tooltiped .tooltip {
	position: absolute;
	right: 0;
	top: 0;
	visibility: hidden;
	opacity: 0;
	transition: ease 1s;
	background-color: #FFF;
	z-index: 999;
}
.tooltiped:hover .tooltip {
	position: absolute;
	top: 20px;
	visibility: visible;
	opacity: 1;
}
.tooltiped .tooltip .tooltip-content {
	max-width: 150px;
}
.tooltiped .tooltip .tooltip-content img {
	width: 200px;
}
.tooltiped .tooltip .tooltip-content,
.tooltiped .tooltip .tooltip-content a {
	color: #fff;
}
.promp {
	border-radius: 3px;
	background: rgba(47, 142, 255, 0.5);
	position: absolute;
	top: -40px;
	right: -100px;
	padding: 3px;
}

Добавляем в шаблон небольшой javascript:

    window.onload = () => {
        document.querySelectorAll(".term").forEach(function(e) {
            e.addEventListener("click", function() {
                navigator.clipboard.writeText(e.innerText).then(function() {
                    e.insertAdjacentHTML('beforebegin', '<div class="promp">скопировано</div>');
                    setTimeout(function(){
                        document.querySelectorAll(".tooltiped .promp").forEach(function(p) {
                            p.remove();
                        });
                    },1000);
                }).catch(function (error) {
                    console.error('Error:', error);
                });
            });
            e.addEventListener("mouseover", () => {
                e.insertAdjacentHTML('afterEnd', '<div class="tooltip"><div class="tooltip-content"><img src="' + e.dataset.url + '" /></div></div>');
            });
        });
    }

Ну и собственно блок с реквизитами:

<p>
    <span class="tooltiped">
        <strong>Карта ( Т-банк ):</strong> <span class="term" data-url="">5536913774062992</span><br>
    </span>
    <span class="tooltiped">
        <strong>USDT (Сеть Solana):</strong> <span class="term" data-url="/uploads/donate/USDT.jpg">HEzoskh3Gmehztu578DWFzq3PBmsoCZSVkzM25AYtCmQ</span> <br>
    </span>
    <span class="tooltiped">
        <strong>BTC:</strong> <span class="term" data-url="/uploads/donate/BTC.jpg">bc1qmnze7qda4eutpzyzjesyr05p0cf4myfrppqz2f</span><br>
    </span>
    <span class="tooltiped">
        <strong>TON:</strong> <span class="term" data-url="/uploads/donate/TON.jpg">UQC7ZauWx4qlSknEd-Ag9NEF5jXq3QT7sd8nJtWRPgWdWBj0</span><br>
    </span>
    <span class="tooltiped">
        <strong>Litecoin:</strong> <span class="term" data-url="/uploads/donate/LTC.jpg">ltc1qlphwcvh0lzmewuupjas3k2uh6d5sjdpcnxyvp0</span><br>
    </span>
    <span class="tooltiped">
        <strong>Ethereum:</strong> <span class="term" data-url="/uploads/donate/ETH.jpg">0x834C17E4bd362AAd6Ba85A665197DE3111f9b7D2</span><br>
    </span>
    <span class="tooltiped">
        <strong>DASH:</strong> <span class="term" data-url="/uploads/donate/DASH.jpg">XgkG5z3zoUATHCKWAP9W76qMTR8938J5ev</span><br>
    </span>
    <span class="tooltiped">
        <strong>XRP:</strong> <span class="term" data-url="/uploads/donate/XRP.jpg">rLnU6E5DSpWNeo2xEDfARpo2jDR1ymWRkh</span><br>
    </span>
    <span class="tooltiped">
        <strong>XLM:</strong> <span class="term" data-url="/uploads/donate/XLM.jpg">GDV3OMVJYL6LJI2HKXNBKQYYVTBQ3LY2LOX2DZVNCYPXV26JI4BZJNLX</span><br>
    </span>
    <span class="tooltiped">
        <strong>HBAR:</strong> <span class="term" data-url="/uploads/donate/HBAR.jpg">0.0.5028861</span><br>
    </span>
    <span class="tooltiped">
        <strong>Solana:</strong> <span class="term" data-url="/uploads/donate/SOL.jpg">HEzoskh3Gmehztu578DWFzq3PBmsoCZSVkzM25AYtCmQ</span><br>
    </span>
    <span class="tooltiped">
        <strong>Cardano:</strong> <span class="term" data-url="/uploads/donate/ADA.jpg">addr1v9pkq5weeqz33kc8aljul5wj4yslr8zxe6flwfan2psvquszy73dg</span>
    </span>
</p>

Готово! =)

31 мая, 2015

Мониторим домены

Небольшой скрипт на php для мониторинга освободившихся доменов в помощь лентяям.

<?php

$domains = array(
    'domain1.ru',
    'domain2.ru'
);

$email = 'my@email.com';

foreach($domains as $domain)
{
    $inf = check_domain($domain);
    if(!isset($inf['free-date']))
    {
        $text = 'DOMAIN ' . $domain . ' FREE';
        mail($email,$text, $text);
    }
}

function check_domain( $domain )
{
    $curl = curl_init();
    curl_setopt( $curl, CURLOPT_URL,'r01.ru/domain/whois/check-domain.php?domain=' . $domain);
    curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($curl,CURLOPT_FOLLOWLOCATION,true);
    $result = curl_exec($curl);
    $info = array();
    $infoField = array(
        'free-date',
        // 'domain','type','descr','state','nic-hdl','person','phone','fax-no','e-mail','reg-till','created','changed', 'registrar'
    );
    foreach($infoField as $field)
    {
        preg_match('#' . $field . ': (.*)#',$result,$m);
        $info[$field] = isset($m[1]) ? strip_tags($m[1]) : '';
    }
    return $info;
}

Запускать скрипт по крону, раз в 5-10 минут.

PS Письма по-умолчанию будут падать в спам.

,

9 апреля, 2014

URL без завершающих слэшей и www

Часто бывает нужно убрать www и завершающие слэши из всех URL. Данную операцию достаточно просто выполнить при помощи кода в .htaccess

#Если вы хотите, чтобы всегда был домен с www
RewriteCond %{HTTP_HOST} ^domen\.ru
RewriteRule ^(.*)$ http://www.domen.ru/$1 [R=301,L]
#Если вы хотите, чтобы всегда был домен без www
RewriteCond %{HTTP_HOST} ^www\.domen\.ru
RewriteRule ^(.*)$ http://domen.ru/$1 [R=301,L]
#Добавить завершающий слэш
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*[^/])$ $1/ [L,R=301]
#Удалить завершающий слэш
RewriteBase /
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /$ [NC]
RewriteRule ^(.*)(/)$ $1 [L,R=301]

12 мая, 2013

Расширение всех файлов в XML формате

Не нашел нигде список всех расширений файлов, но зато наткнулся на сайт http://open-file.ru в котором приведен весь список расширений. Решил написать небольшой скрипт, который вытянет все расширения с описаниями и типами в XML файл.

<?php

set_time_limit(0);
$url = 'http://open-file.ru';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$result = curl_exec($ch);
preg_match('~<p>(.*)</p>~',$result,$match);
preg_match_all('~<a href="(/types/.*/)">.*</a>~Us',$match[1],$match);
$extension = array();
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<extensions>';
foreach( $match[1] as $link )
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, ( $url . $link ));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    $result = curl_exec($ch);
    preg_match( '~<table>(.*)</table>~Us', $result, $table );

    $reg = array(
        '~<tr><td>.*<a href="/types/.*">(.*)</a>.*</td>',
        '<td>.*<a href="/types/.*/">(.*)</a>.*</td><td>',
        '.*<a href="/types/.*">(.*)</a>.*</td></tr>~'
    );

    preg_match_all(implode($reg),$table[1],$data);
    foreach( $data[1] as $key => $ext )
    {
        $xml .= '
            <extension>
                <name><![CDATA[' . $ext . ']]></name>
                <type><![CDATA[' . $data[2][$key] . ']]></type>
                <description><![CDATA[' . $data[3][$key] . ']]></description>
           </extension>
';
   }
}

$xml .= '</extensions>';

file_put_contents('tmp/extensions.xml' , iconv( 'cp1251', 'utf8', $xml ) );

,

17 февраля, 2013

Скрипт для отправки обновлений на почту

Для одного проекта понадобилось высылать заказчику обновления ( pack ), так как это рутинная задача, я решил написать простой скрипт на shell:

 

#!/bin/sh 

# Мыльник куда отправляем пакет с обновлениями 
EMAIL=$1 

# Директория с проектом 
PROJECT=/var/www/my_project 

# Дата ( для заголовка письма и названия файла архива с обновлением ) 
DATE=`date +%d-%m-%Y_%H-%M` 

# Название файла архива с обновлением 
TARNAME=pack_my_project_$DATE.tgz 

# Локальная директория в которой сохраняются архивы с обновлениями 
PACK=pack/$TARNAME 

# Изменения в проекте ( git ) 
CHANGE=`cd $PROJECT && git diff --stat | awk 'NF != 7 {print $1}' && cd - > /dev/null` 

# Тема письма с архивом обновления 
SUBJECT='Обновление project от $DATE' 

# Тело письма, опционально 
BODY='' 

# Создаем архив с изменениями и отправляем письмо
cd $PROJECT && \
tar czf $PACK $CHANGE > /dev/null && \
( ( echo $BODY $CHANGE ); uuencode $PACK $TARNAME ) \ 
| mail -s "Обновление project от $DATE" $EMAIL && \
cd - > /dev/null 

в .zshrc прописываем путь к директории к скрипту и ставим разрешение на выполнение файла

Отправляем:

 $ my_project_update.sh test@gmail.com 

Сообщение с паком уйдет на почту.

TODO: Мою задачу скрипт решает полностью, но его можно доработать:
1) проверка наличия параметра $1
2) проверка, что в проекте реально есть изменения

, ,

Быстрое добавление множества директорий в .gitignore

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

 $ ls -l uploads | awk {'print "/uploads/"$9"/*"'} > ../.gitignore 

Дело сделано, нужные директории теперь не будут включены в репозитарий.

19 декабря, 2010

Шелл на PHP

Небольшая тулза на PHP+Ajax, которая позволяет выполнять shell команды.

<?php
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
    if (!empty($_POST['command'])) {
        exec($_POST['command'], $result);
        if (is_array($result)) {
            foreach ($result as $str)
                $res[] = htmlspecialchars($str);
            $res = isset($res) ? implode("<br />", $res) : '';
        } else {
            $res = $result;
        }
        echo $res;
    }
    exit();
}
?>

<!DOCTYPE HTML>
<html>
<head>
    <title>Shell</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript">
        function clear(c) {
            c.attr("value", "");
        }

        $(document).ready(function () {
            var c = $("input[name='command']");
            clear(c);
            c.focus(function () {
                $("span").hide();
            });
            c.blur(function () {
                $("span").show();
            });
            c.keyup(function (event) {
                if (event.keyCode == 13)
                    $.post('sh.php', {
                        command: $(this).val()
                    }, function (data) {
                        $("div").html(data);
                        clear(c);
                    });
            });
        });
    </script>
    <style type="text/css">
        * {
            background: #000;
            border: 0;
            color: green;
            font: 62.5% Arial, Helvetica, sans-serif;
            width: 100%;
        }

        body {
            font-size: 1.5em;
            margin: 0;
            padding: 0;
        }

        input {
            background-color: #000;
            font-size: 1em;
            width: 80%;
        }

        div {
            background: #000;
            font-size: 1em;
            height: 100%;
            min-height: 20px;
            width: 90%;
        }

        strong {
            color: #fff;
        }

        hr {
            color: #fff;
            background-color: #fff;
            height: 1px;
            margin-top: 0;
            width: 100%;
        }

        blink {
            font-size: 1.5em;
        }

        p {
            background: #fff url(http://www.catb.org/~esr/hacker-emblem/glider.png) no-repeat top right;
            display: block;
            height: 55px;
            right: 20px;
            position: absolute;
            width: 55px;
        }
    </style>
</head>
<body>
<?php system('hostname')?>&gt;<span><blink>_</blink></span>
<input name="command"/>
<hr/>
<p></p>
<div></div>
</body>
</html>

28 июля, 2010

Скрипт добавления нового виртуального хоста

Как-то поднадоело мне постоянно редактировать вручную httpd.conf и /etc/hosts и я решил написать скрипт, который бы позволил автоматизировать этот процесс
Вот такой скрипт:

#!/bin/sh

# Константы:
HOSTS='/tc/hosts'; # Путь к файлу hosts
HTTPD_CONF='/etc/httpd/conf/extra/httpd-vhosts.conf';

# Путь к файлу с настройками виртуальных хостов
DIR_HTTP='/srv/http/'; # Путь к директориям с хостами
IP_MASK='127.0.0.'; # Маска по которой будет формироваться новый IP
INDEX_FILE='index.php'; # Index файл в корневой папке нового виртуального хоста
DIR_LOG='/var/log/httpd/'; # Путь к папке с логами
EMAIL_ADMIN='wikide@gmail.com'; # Email админестратора

# Функция вывода ошибок
get_error() {
    echo $1;
    exit 0;
}

# Функция проверки ip
check_ip() {
    if [ "`cat $HOSTS | grep \"$ip\"`" ]; then
        echo 1;
    fi
}

# Проверяем наличея параметра с именем хоста
if [ "$1" ]; then
    if [ "$2" ]; then
        # Если задан свой IP
        new_ip=$2;
        if [ "`check_ip $new_ip`" ]; then # Проверка на наличее в файле
            get_error 'Такой ip адрес - '$new_ip' уже занят. Введите другой или пусть скрипт '$0' сам сгенерирует ip адресс для нового хоста.';
        fi;
    else
        # Получаем IP автоматически
        new_ip=$IP_MASK$((`tail -1 $HOSTS | awk '{ split($1, ip, "."); print ip[4]}'`+1));
    fi

    # Если корневая папка нового хоста уже существует
    if [ -d $DIR_HTTP$1/ ]; then
        get_error 'Директория '$1' уже есть в '$DIR_HTTP'. Подберите другое имя.';
    else
        # Создаем корневую директорию виртуального хоста
        mkdir $DIR_HTTP$1;
        echo -e "
    <html>
     <head>
      <title>New host</title>
     </head>
     <body>
        <h1>Created host '$1'!</h1>
     </body>
    </html>" > $DIR_HTTP$1'/index.php';
  
    # Запись в hosts
        sudo echo $new_ip  $1 | sudo tee -a $HOSTS 1>/dev/null;

    # Запись в конфиг Apache
        sudo echo -e "#Create date: `date '+%F %T'`
          DirectoryIndex $INDEX_FILE
          ServerAdmin $EMAIL_ADMIN
          DocumentRoot \"$DIR_HTTP$1/\"
          ServerName $1
          ServerAlias $1
          ErrorLog \"$DIR_LOG$1.log\"
          CustomLog \"$DIR_LOG$1\" common" | sudo tee -a $HTTPD_CONF 1>/dev/null;

        # Перезапускаем сервер
        sudo apachectl restart;

        # Выводими сообщение

        echo 'Виртуальный хост "'$1'" успешно создан'
    fi
else
    get_error 'Нужно обязательно указать название нового хоста $0 NAME_HOST [IP_HOST]';
fi

exit 0;

,

27 июля, 2010

Скрипт запуска wifi в ARCH Linux

Небольшой скрипт для подключения к сетям wifi в ARCH linux

#!/bin/bash

# Определяем интрфейс ( в моем случае это - wlan0)
if [ "$2" ]; then 
	dev=$2;
else 
	dev="wlan0";
fi

# Действие
case "$1" in
	start)
		sudo ifconfig $dev up;
		sudo wpa_supplicant -B -i$dev -c/etc/wpa_supplicant.conf;
		sleep 3;
		sudo dhcpcd $dev 2&gt;/dev/null;
	;;
	stop)	
		sudo killall -9 dhcpcd 3&gt;/dev/null;
		sudo killall -9 wpa_supplicant 3&gt;/dev/null;
		sudo ifconfig $dev down;
	;;
	list)
		sudo ifconfig $dev up;
		sleep 1;
		sudo iwlist $dev scanning;
		sudo ifconfig $dev down;
	;;
	restart)
		$0 stop;
		$0 start;
	;;
	status)
		echo -n 'IP arrdess: '; ifconfig wlan0 | grep "inet addr" | awk '{print $2}' | sed 's/addr://'
		echo -n "Essid: "; iwconfig wlan0 | grep "Ralink STA" | awk '{print $4}' | sed 's/ESSID://'
	;;
	*)

	if [ "$1"  ]; then
		echo "usage: $0 {start|stop|list|restart}"; 
	else 
		echo "Restarting";
		$0 restart;
	fi

esac

exit 0

Вот такой вот скрипт :)

,

26 июля, 2010

Статус аккумулятора в приглашении командной строки

Вот очередной велосипед на тему показа статуса аккумулятора для нэтбука на ARCH Linux :)

Вот такой получается скрипт на sh (думаю все ясно из комментов):

#!/bin/zsh

# Определяем уровень заряда аккумулятора на текущий момент
remaining_bat=`cat /proc/acpi/battery/BAT0/state | grep remaining | awk {'print $3'}`;

# Определяем 100% заряда для аккумулятора
full_bat=`cat /proc/acpi/battery/BAT0/info | grep full | awk {'print $4'}`;

# Определяем подключён сетевой провод или нет
stat=`cat /proc/acpi/battery/BAT0/state | grep charging | awk {'print $3'}`;

if [ $stat = 'charging' ]; then
stat='+'; # Провод подключён ( ноут зяряжеается )
else if [ $stat = 'charged' ]; then
stat=''; # ( Аккумулятор зяряжен)
else
stat='-'; # Провод не подключён ( ноут разряжается )
fi
fi

# получаем заряд батареи в % ( Школьная математика - Рулит! :) )
bat=$(($remaining_bat*100/$full_bat));

# основные цвета ( ESC - последовательности, подробнее - $ man console_codes )
RED="\033[31m"; # Красный
YELLOW="\033[33m"; # Жёлтый
WHITE="\033[38m"; # Белый

# Цвет по-умолчанию
DEFAULT="\033[0m";

if [ $bat -lt 10 ]; then # Если заряд аккамулятора меньше 10% (краасные цвет)
result="$RED$stat$bat";
else if [ $bat -lt 30 ]; then # Если заряд аккамулятора меньше 30% (жёлтый цвет)
result="$YELLOW$stat$bat";
else
result="$WHTE$stat$bat"; # Заряд аккамулятора больше 30% ( белый цвет )
fi
fi

# Выводим результат
echo -e $result%%$DEFAULT;

exit 0;

Далее говорим zsh о том, что нужно выводить в PROMPT результат этого скрипта.
В файле ~/.zshrc в функции precmd() прописываем где-нибудь в начале:

precmd() {
   BAT=`binf.sh`;
   PROMPT="battery:(`echo $BAT`)::%{$reset_color%}%{$fg_bold[green]%}%m {$reset_color%}::%{$fg_bold[crey]%}[ %~ ]%{$rese+t_color%}&gt; "
.....

Как-то вот так, где binf.sh — скрипт выше.
Обязательно нужно, чтобы binf.sh лежал по пути в переменной PATH, я для этой цели создал папку bin в домашней директории и сделал ссылку на файл в папке /bin

В precmd() — можно запихнуть любые команды, которые будут выполнятся при обновлении командной строки.

2 июля, 2010

HTML 5

[announce]Пора переходить[/announce]

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

Вот что новенького появилось (движение в сторону упрощения, что не может не радовать :) ):

  • Логическая разбивка (header, footer, nav …) и это есть прикольно! :)
  • Доктайп стал очень простым — !DOCTYPE html
  • У ссылок можно использовать атрибут — target
  • Тэг script может не содержать никакие атрибуты
  •  

    В IE чтобы вся эта красота заработала нужно вставить небольшой код javascript в документе на HTML5:

    Так:

    <!-- [if IE] -->
    <script>
    document.createElement('header');
    document.createElement('nav');
    document.createElement('section');
    document.createElement('article');
    document.createElement('aside');
    document.createElement('footer');
    </script>
    <!-- [endif]-->
    

    Или так:

    <!--[if IE]>
      <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    

     

    Конечно я уже привык к XHTML и мне даже нравилась его строгость, но ничего не поделаешь, время идет и приходят новые более совершенные технологии. :-D

    Я прочитал из этого ресураса о html5 http://dimox.name/hello-html5-goodbye-xhtml2/

26 мая, 2010

Подключение tinymce

[announce]Постоянно забываю как подключать его.. Пусть будет здесь![/announce]
Подключение TinyMCE к textarea по классу

tinyMCE.init({	
...
mode : "specific_textareas",
editor_selector : "mceEditor"
});

Подключение TinyMCE к textarea по ID

tinyMCE.init({
...
mode : "exact",
elements : "elm1,elm2"
});

...

<textarea id="elm1" ...

Источник: http://wiki.moxiecode.com/index.php/TinyMCE:Configuration/mode

22 декабря, 2009

JQuery Uploadify

[announce]Удобный плагин для загрузки файлов на сервер. [/announce]

Дескрипшон

http://www.uploadify.com — удобный инструмент если нужно быстро создать в CMS возможность загрузки нескольких файлов.Плагин для JQuery.

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

Файлы

<script type="text/javascript" src="http://aa/admin/spaw2/empty/jquery.uploadify.v2.1.0.min.js"></script>
<script type="text/javascript" src="http://aa/admin/spaw2/empty/swfobject.js"></script>

Код

$(document).ready(function() {
 $("#uploadify").uploadify({   
     'uploader'    :'uploadify.swf',
     'script'      : 'functions.php',   
     'checkscript' : 'check.php',   
     'cancelImg'   : 'cancel.png',
     'queueID'     : 'fileQueue',   
     'auto'        : true,   
     'multi'       : true,   
     'fileDesc'    : 'jpg',   
     'fileExt'     : '*.jpg',  
     'onComplete'  : function(event,queueID,fileObj,response,dat{$('#response').append(response);}  });
});

Настройки

uploader — путь до самого флэш загрузчика uploadify.swf
script — это путь до нашего файла обработчика, у меня это файл functions.php, но в архиве с библотекой он именуется как uploadify.php.
checkscript
— путь до скрипта, который будет проверять наш файл до загрузки его на сервер. В файле, идущем в архиве с плагином, проверяют существования файла с таким же именем на сервере.
cancelImg — путь до картинки, которая будет символизировать удаления файла.
queueID
— id элемента, в котором будет содержаться список выбранных нами файлов. По умолчанию он создаётся ниже браузерной кнопки выбора файла.
auto — параметр, отвечающий, будут ли файлы загружаться автоматически сразу после их выбора, или нет. Если стоит значение false, то для начала загрузки можно использовать этот код:
  <a href="javascript:$('#uploadify').uploadifyUpload();">Загрузить файлы.</a>

Естественно, можно повесить вместо ссылки картинку или кнопку, тут уже на Ваш выбор.
multi
— будет ли наш плагин служить для загрузки нескольких файлов, иль не будет.
fileDesc
— типы файлов в диалоге выбора.
fileExt
— расширения файлов, разрешенных для загрузки. Незабываем добавить эти типы файлов и в fileDesc, иначе не сможете выбрать эти файлы в диалоговом окне.
onComplete
— функция, которая будет вызвана сразу после загрузки файла. Данная функция будет вызываться каждый раз, как будет загружен очередной файл.
onAllComplete
— функция, которая будет вызвана сразу после загрузки всех файлов.
buttonText — текст на кнопке (на время написания этого текста на кнопки могла отображатся только надпись на английском языке).

Дока — http://www.uploadify.com/documentation/
Плагин — http://www.uploadify.com

Источник — http://habrahabr.ru/blogs/jquery/71772/