PHP Composer – some commands and tricks

Directory structure:

|   composer.json
|   composer.phar
|   index.php
|
+---app
|   +---controller
|   |       Home.php
|   |
|   \---model
|           FirstDb.php
|
\---vendor
    |   autoload.php
    |
    \---composer
            autoload_classmap.php
            autoload_namespaces.php
            autoload_psr4.php
            autoload_real.php
            autoload_static.php
            ClassLoader.php
            LICENSE

1. Standard case – with namespaces

root/composer.json

{
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

root/app/controller/Home.php

<?php
namespace App\Controller;

class Home{

	public function index(){
		echo "Hello from Home->Index!";
	}
}

root/app/model/FirstDb.php

<?php
namespace App\Model;

class FirstDb{
	public function db(){
		echo "Hi from first DB";
	}
}

root/index.php

<?php 
use App\Controller\Home;
use App\Model\FirstDb;

require_once __DIR__ . '/vendor/autoload.php';

$h = new Home();
$fdb = new FirstDb();

echo $h->index()."\n";
$fdb->db();

2. Without namespaces

root/composer.json

{
    "autoload": {
        "psr-4": {"": ["app/controller", "app/model"]}
    }
}

root/app/controller/Home.php

<?php

class Home{

	public function index(){
		echo "Hello from Home->Index!";
	}
}

root/app/model/FirstDb.php

<?php

class FirstDb{
	public function db(){
		echo "Hi from first DB";
	}
}

root/index.php

<?php 
require_once __DIR__ . '/vendor/autoload.php';

$h = new Home();
$fdb = new FirstDb();

echo $h->index();
$fdb->db();

3. Mix usage

root/composer.json

{
    "autoload": {
        "psr-4": {
            "": "app/"
        }
    }
}

root/app/controller/Home.php

<?php
namespace controller;

class Home{

	public function index(){
		echo "Hello from Home->Index!";
	}
}

root/app/model/FirstDb.php

<?php
namespace model;

class FirstDb{
	public function db(){
		echo "Hi from first DB";
	}
}

root/index.php

<?php 
require_once __DIR__ . '/vendor/autoload.php';

$h = new controller\Home();
$fdb = new model\FirstDb();

echo $h->index();
$fdb->db();

4. Composer addPsr4() without cnahge composer.json – dynamically add classes

root/composer.json

{
    "name": "some/test",
    "require": {}
}

root/app/controller/Home.php

<?php
namespace App\Controller;

class Home{

	public function index(){
		echo "Hello from Home->Index!";
	}
}

root/app/model/FirstDb.php

<?php
namespace App\Model;

class FirstDb{
	public function db(){
		echo "Hi from first DB";
	}
}

root/index.php

<?php 
use App\Controller\Home;
use App\Model\FirstDb;

$loader = require __DIR__ . '/vendor/autoload.php';
$loader->addPsr4('App\\', 'app/');

$h = new Home();
$fdb = new FirstDb();

echo $h->index()."\n";
$fdb->db();

5.Some important commands

Some important commands:

To initially install the defined dependencies:
php composer.phar update

to make sure the vendor directory is up in sync with your composer.lock file
php composer.phar install

To update to the latest versions
php composer.phar update

After adding the autoload field, you have to re-run this command:
php composer.phar dump-autoload

php composer.phar dump
calls composer dump-autoload.

how to create a composer.json by hand
php composer.phar init

To list all of the available packages
php composer.phar show

It will replace your composer.phar with the latest version:
php composer.phar self-update


all directories or files to search for classes:
{
    "autoload": {
        "classmap": ["src/", "lib/", "Something.php"]
    }
}
Wildcards (*) are also supported in a classmap paths, and expand to match any directory name:
{
    "autoload": {
        "classmap": ["src/addons/*/lib/", "3rd-party/*", "Something.php"]
    }
}


if your package includes PHP functions that cannot be autoloaded by PHP:
{
    "autoload": {
        "files": ["src/MyLibrary/functions.php"]
    }
}




HELP
=========================
to see the complete list of commands
composer list

--help combined with any of those can give you more information

Share and Enjoy !

Shares

nginx portable web server

Трябва ми лек сървар с който да управлявам едн компютър, който ползвам за нещо като локален NAS. Apache тотално не ми се вписва в сметките, защото напоследък брах ядове с пълното му деинсталиране от системата. Затова се спрях на конкурента му nginx. По-долу поствам някои интересни моменти от тестовете, които направих под Windows.
За да мога да достъпвам сървара в локална мрежа, трябваше да променя настройките на Firewall-а на Windows 10. В моя случай промених настройки на firewall на Nod32, който е асоцииран по подразбиране в firewall-a на Win.

Изтеглих Mainline version на nginx от тук: nginx download

Разархивирах го в една директория и му промених conf/nginx.conf така, че да отговаря на моите нужди. Важно е да се отбележи, че предварително имам инсталиран PHP 7.2, който е добавен в променливите на обкръжението на Win10.

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    # gzip  on;

    server {
        listen       80;
        server_name  192.168.0.21;

        location / {
            root F:\\nginx-1.19.7\\site\\local;
            index  index.php;
            try_files $uri $uri/ /index.php?$args;
        }

        #rewrite ^/(.*)$ /index.php/$1 last;

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            root           F:\\nginx-1.19.7\\site\\local;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

Реда:

try_files $uri $uri/ /index.php?$args;

казва на сървара първо да потърси файл, след това директория и най-накрая ако не намери предните две да потърси index.php, като всичко след името на домейна го постави като аргумент. Примерно:
https://localhost/system-info
ще се преобразува в:
https://localhost/index.php?/system-info
По този начин мога да ползвам френдли адресиране, вместо да изписвам остарелите GET променливи. В Apache се ползва .htaccess за тая цел. Но в nginx тези инструкции се поместват в основния кофигурационен файл.

За да спирам и пускам сървара използвах batch код, който намерих някъде в мрежата. Коментирал съм с REM кодове в скрипта, които могат да са полезни след време, но които не са ми необходими, като спиране и пускане на MySQL. Напоследък за леки проекти ползвам основно SQLite с RedBeanPHP като ORM:

@echo off
REM cd C:\WebServer\nginx


IF "%1" == "stop" (
	GOTO STOPSERVER
)else IF "%1" == "start" (
	GOTO STARTSERVER
)else (
	echo Use these commands:
	echo.
	echo myserver start
	echo myserver stop
)
GOTO END

:STARTSERVER
REM QPROCESS * | find /I /N "mysqld.exe">NUL
REM IF "%ERRORLEVEL%"=="0" (
REM	 echo MYSQLD is already running.
REM )else (
REM 	RunHiddenConsole.exe mysqld --console
REM	echo MYSQLD is now running.
REM )

QPROCESS * | find /I /N "nginx.exe">NUL
IF "%ERRORLEVEL%"=="0" (
	echo NGINX is already running.
)else (
	RunHiddenConsole.exe nginx
	echo NGINX is now running.
)

QPROCESS * | find /I /N "php-cgi.exe">NUL
IF "%ERRORLEVEL%"=="0" (
	echo PHP-CGI is already running.
)else (
	RunHiddenConsole.exe php-cgi -b 127.0.0.1:9000
	echo PHP-CGI is now running.
)

echo.
echo To stop, type "myserver stop"

GOTO END

:STOPSERVER

REM QPROCESS * | find /I /N "mysqld.exe">NUL
REM IF "%ERRORLEVEL%"=="0" (
REM 	taskkill /F /IM mysqld.exe>NUL
REM 	echo MYSQLD ended successfully.
REM )else (
REM 	echo MYSQLD is not running
REM )

QPROCESS * | find /I /N "nginx.exe">NUL
IF "%ERRORLEVEL%"=="0" (
	::nginx -s stop
	taskkill /F /IM nginx.exe>NUL
	echo NGINX ended successfully.
)else (
	echo NGINX is not running
)

QPROCESS * | find /I /N "php-cgi.exe">NUL
IF "%ERRORLEVEL%"=="0" (
	taskkill /F /IM php-cgi.exe>NUL
	echo PHP-CGI ended successfully.
)else (
	echo PHP-CGI is not running
)

:END

Запазих по-горния код в директорията с exe-то на nginx в файла myserver.bat. Пускане и спиране на сървара става с командите:

myserver start
myserver stop

За файлов фмениджър на NAS-чето за сега съм се спрял на Tiny File Manager. Този файлов мениджър е поместен само в един файл и има достатъчно опции за редактиране, които са ми напълно достатъчни.

Това е. Получи се много гот.

Share and Enjoy !

Shares

PHP Captcha Generator – с възможности за настройка

В различните ми проекти с PHP съм ползвал различни Captcha генератори, за да се пазя от спамери и ботове. Но винаги нещо ми е липсвало или са били прекалено грамадански за семплите ми нужди. За това си написах един клас, който лесно да мога да интегрирам в проектите. Всъщност идеята беше друга – да направя голямо количество предефинирани капчи и да ги набутам в SQLite файл, така скоростта на зареждане става муцка. Това и направих. Но така или иначе написах голяма част от кода, та реших да направя и един самостоятелен клас. В последствие, ако ми текне музата, мога да напиша и туториал и със сесии да демострирам, как използвам капчата в реални условия.

Моя Captcha Generator има няколко готини опции за настройка:

  • използване на множесвно TTF-шрифтове. Аз ползвам такива от https://fonts.google.com
  • настройка големината на шрифта
  • настройка на отстоянието между отделните знаци
  • дефиниране на различни ъгли за наклон на знаците
  • дефиниране на собствен масив от знаци

Captcha generator класа с много простичко примерче може да се изтегли от тук:
https://blog.nediko.info/examples/captcha_generator/CaptchaGen_PHP.zip

А ето и един видео урок, който направих набързо, за да е ясно как се настройва генератора:


Share and Enjoy !

Shares

Amascrap – amazon price scraper

Amazon price scraper - извличане и проследяване на цени
Amascrap е програма тип “web scraper”, която извлича и логва цени от Amazon.co.uk. Програмата е базирана на PHP, HTML, Javascript (jQuery). Вградил съм Traktor на цените, за да имат някаква проследяемост във времето. Скриптовете могат да се използват и като Web-сайт.

Програмата я написах за мен, защото често ми се налага да пазарувам от Amazon.co.uk. Забелязах, че в сайта доста продукти си сменят цените през няколко дни и има значение, дали ще си купиш нещо с 10 паунда по-ниска цена. Все пак съм си българче :). Traktora позволява да следиш, през колко време някой продукт си сменя цената, което си е идеална статистика. Помогна ми да разбера, че някои продукти имат абсолютно точен цикъл на смяна на цената. Особено добре се вижда преди или след празници.
Не съм писал демон за автоматичен ъпдейт, за това цените трябва да се ъпдейтват ръчно. При много продукти и ъпдейт на всички се получава лаг, който няма как да се избегне. Все пак нямам достъп до базата данни на Амазон, нит ползвам API. Чист и класически Web-скрапер с XPath и cURL под PHP.
За GUI използвах PHP Desktop с MSIE (не ме целете с камъни, просто Chrome вдигна много мегабайтите).

Кратък видео урок, как се работи с програмата:
[flv:https://blog.nediko.info/examples/amascrap/Amascrap-v.0.01-Tutorial.flv https://blog.nediko.info/examples/amascrap/Amascrap.jpg 584 406]

Програмата с сорс-кода може да се изтегли от тук:
Amascrap v.0.04 – Ъпдейт на 13.06.2016. Оправени са проблеми при сваляне на данните през HTTPS.

Share and Enjoy !

Shares




Laravel – root dir post-request

Има един досаден бъг в Laravel 4.2. Не иска да обработва post-заявка, насочена към root-адреса. Говоря за това:

1
2
3
Route::post('/',function(){
 // ...
});

В такива случаи Laravel сеправи на чук и просто рефрешва страницата.
Открих 2 трики-метода за заобикаляне на бъг-а:
1. Поставя се шпация, ако формата е насочена към текущата страница:

1
{{Form::open(array('url'=>' ','method'=>'post'))}}

2. Пишем точно към кой адрес е насочена формата:

1
{{Form::open(array('url'=>'/index.php','method'=>'post'))}}

Share and Enjoy !

Shares




Извличане на цветове от картинка с php

Имам една идея за автоматична смяна на цветната схема на Bootstrap-базиран сайт. За целта ми трябва просто извличане на цветовете от картинка с php-скрипт.
За базови цветове създавам проста картинка с квадратчета, като тази:
php extract color from image
За да извлека цветовете от отделните квадратчета използвам php-функцията imagecolorat, която взима цвета на пиксел при зададени кооординати. Координатната система е нулирана в горния ляв ъгъл:
imagecolorat - coordinates
Примерен скрипт в който използвам извличане цвета на пиксел, който се намира горе-долу по средата на всеки правоъгълник:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
// $rgb е array
function rgb2hex($rgb) {
   $hex = "#";
   $hex .= str_pad(dechex($rgb[0]), 2, "0", STR_PAD_LEFT);
   $hex .= str_pad(dechex($rgb[1]), 2, "0", STR_PAD_LEFT);
   $hex .= str_pad(dechex($rgb[2]), 2, "0", STR_PAD_LEFT);
 
   return $hex;
}
 
function get_color_from_pixel($img, $x, $y){
    $im = imagecreatefrompng($img);
    $rgb = imagecolorat($im, $x, $y);
    $r = ($rgb >> 16) & 0xFF;
    $g = ($rgb >> 8) & 0xFF;
    $b = $rgb & 0xFF;
 
    return rgb2hex(array($r, $g, $b));
}
 
// ===================================================
// EXAMPLE
 
$image = "image.png";
$y = 24;
$x_ar = array(33, 103, 177, 244, 315, 385, 454, 526, 593);
 
foreach ($x_ar as $x) {
    $colors[] = get_color_from_pixel($image, $x, $y);
}
print_r($colors);
?>

Резултат:

1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [0] => #36261c
    [1] => #d5c187
    [2] => #6ecddf
    [3] => #827b3a
    [4] => #2a7d94
    [5] => #9db079
    [6] => #82796d
    [7] => #a7c6da
    [8] => #d54c06
)

Изтегляне на скрипта и картинката: PHP-get_colors_from_image.zip

Share and Enjoy !

Shares




PHP рекурсивно обхождане на дървовидна база данни

Много често се налага да се работи с дървовидни бази данни. С тях могат да се изграждат структури с дъщерни елементи, като например дървовидни менюта за сайт с категория, подкатегория, секция.
Ето едно примерно обхождане на подобна база данни с рекурсия:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
$arr = array(
    // $id, $parent_id, $name
    array(1, 0, "edno"),
    array(2, 0, "dve"),
    array(3, 1, "edno-edno"),
    array(4, 3, "edno-edno-edno"),
    array(5, 1, "edno-dve"),
    array(6, 2, "dve-edno"),
    array(6, 1, "edno-tri")
);
 
function recurse($arr, $pid, $space = '') {
    $output = '<ul>';
 
    foreach ($arr as $key => $ar) {
 
        if ($ar[1] == $pid) {
 
            $output .= "<li>" . $ar[2] . "\n";
            // iztrivane na obhodenite elementi
            $pid_temp = $ar[0];
            unset($arr[$key]);
 
            if ($children = recurse($arr, $pid_temp, $space . '_')) {
                if ($children != '<ul></ul>')
                    $output .= $children;
            }
            $output .= "</li>";
        }
    }
 
    return $output . "</ul>";
}
 
echo recurse($arr, 0, '');

В резултат се получи една чудесна списъчна структура:
Дървовидно обхождане с рекурсия

Share and Enjoy !

Shares




Netbeans дебъгване на PHP-код с Xdebug

Не знам защо до сега не съм използвал възможностите за дебъгване на PHP. Може би от глупост, щото едва ли не ми се е налагало. Е, да но вече като знам, че е добре да се дебъгва, едва ли ще пропусна да използвам тази благинка.
Нямам по-читав редактор за PHP, освен портабъл версия на Netbeans 7.4. Няма инсталирана и чиста Java (необходима, за да работи IDE-то), за това ще използвам портабъл версия – OpenJDKPortable_7_Update_9_b02_Development_Test_1.paf.exe.
Портабъл версиите понякога се държат много идиотски. А защо не използвам инсталатори е една друга тема. И за да работи всичко както трябва се наложи да направя простотията да инсталирам 3-те “инструмента” в следните директории:
NetBeans 7.4: C:\installed\soft\NetBeans_PHP_7.4_Portable
OpenJDK 7: C:\installed\soft\CommonFiles\java
PHP 5.4.23: C:\installed\soft\php

След стартиране на NetBeans, видях, че всичко е наред, само дето не му работеше дебъгването. Това се оправя по следния начин:
1. Download на php_xdebug-2.2.5-5.4-vc9-nts.dll от тук
2. Записва се в директорията: C:\installed\soft\php\ext
3. Редактира се файла php.ini, като в края му се добавя:
zend_extension='C:\installed\soft\php\ext\php_xdebug-2.2.5-5.4-vc9-nts.dll'
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000

И почва да се пие бира и да се дебъгва неистово.

Share and Enjoy !

Shares




Guest Blogging Articles – система за гест-статии

Article-X е проста система за писане на статии от гост-потребители. Системата я написах така, че да наподобява малко CMS. Може да се настройва.
Article-X - guest blogging system
Подробности и видео урок как се ползва могат да се намерят тук:
Aricle-X – Guest Blogging System
Фронт-демо на системата тук.

Share and Enjoy !

Shares




PHP-file UTF-8 encoding

Попаднах на стар хостинг (с php 5.2.3), който прецаква енкодинга при ъплауд на php-файлове. Изключително досаден проблем. Пробвах да вкарвам разни дивотии в .htaccess, но нищо не помогна. Ей такива неща опитах:

AddDefaultCharset utf-8
AddCharset utf-8 .php
DefaultLanguage en-US

Единствения шанс, който ми остана беше да накарам интерпретатора да каже на сървара, че файла трябва да се излъчи в UTF-8 encoding. По-долния код се поставя преди рендването на съдържанието:

<?php header('Content-Type: text/html; charset=utf-8'); ?>

Доста удобно за моя стил на програмиране :).

Share and Enjoy !

Shares