Instagram open api requests (09.03.2017)
Parse instagram account and get all photos
<?
$ig = json_decode(file_get_contents("https://www.instagram.com/kevin/media/"));
while($ig->more_available) {
  foreach($ig->items as $item) {
    echo $item->id."<br>";
    echo "<img src=".$item->images->standard_resolution->url."><br>";
    echo $item->caption->text."<br>";
  }
  $ig = json_decode(file_get_contents("https://www.instagram.com/kevin/media/?max_id=".$item->id));
}
?>
Get photos details by hashtag (filter auditory)
<?
$ig = json_decode(file_get_contents("https://www.instagram.com/explore/tags/friday/?__a=1"));
while($ig->tag->media->page_info->has_next_page) {
  foreach($ig->tag->media->nodes as $item) {
    echo $item->id." ".$item->owner->id."\n";
  }
  $ig = json_decode(file_get_contents("https://www.instagram.com/explore/tags/friday/?__a=1&max_id=".$ig->tag->media->page_info->end_cursor));
}
?>
PHP
Google Calendar events on the SyncML device (28.06.2016)
Get Google Calendar events on the SyncML compatible phone.

After Google stoped it’s SyncML service in 2013 there’s no free simple solution to synchronize the Calendar with SyncML device (like Nokia s40 in my case). Another reason to setup own server is outdated technology so last online sync services may go down soon.
We will install Funambol SyncML server on linux and use Google Calendar PHP API to import Calendar events to Funambol mysql database.

Funambol installation instruction:

Install Funambol
wget -O funambol-10.0.3-x64.bin https://sourceforge.net/projects/funambol/files/bundle/v10/funambol-10.0.3-x64.bin/download
chmod +x funambol-10.0.3-x64.bin
./funambol-10.0.3-x64.bin

Download and insert mysql-connector-java:
wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.39.tar.gz
tar -zxvf mysql-connector-java-5.1.39.tar.gz
cp ./mysql-connector-java-5.1.39/mysql-connector-java-5.1.39-bin.jar  /opt/Funambol/tools/jre-1.6.0/jre/lib/ext/
cp ./mysql-connector-java-5.1.39/mysql-connector-java-5.1.39-bin.jar  /opt/Funambol/pim-listener/lib/
cp ./mysql-connector-java-5.1.39/mysql-connector-java-5.1.39-bin.jar  /opt/Funambol/inbox-listener/lib/

Change /opt/Funambol/ds-server/install.properties:
dbms=mysql
jdbc.classpath=/opt/Funambol/tools/jre-1.6.0/lib/ext/mysql-connector-java-5.1.14-bin.jar
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/funambol?characterEncoding=UTF-8
jdbc.user=funambol
jdbc.password=funambol

Create mysql database:
mysql> create database funambol;
mysql> GRANT ALL PRIVILEGES ON funambol.* TO 'funambol'@'localhost'  IDENTIFIED BY 'funambol';
/opt/Funambol/bin/install

Make init script to start Funambol as service (founded here). We don’t actually need all services from the instruction, also it’s memory consuming, so we’ll start only funambol-server.
/etc/init.d/funambol:
#!/bin/sh

cd `dirname $0`
FUNAMBOL_HOME=`(cd /opt/Funambol ; pwd)`
DS_SERVER_HOME=$FUNAMBOL_HOME/ds-server

if [ ! -d $FUNAMBOL_HOME/config ]; then
#
# maybe we are in Funambol/tool/bin
#
FUNAMBOL_HOME=$FUNAMBOL_HOME/..
DS_SERVER_HOME=$FUNAMBOL_HOME/ds-server
fi

# Setting the JAVA_HOME to the JRE in the bundle if not set or if not correctly set
if [ -z "$JAVA_HOME" ]; then
export JAVA_HOME=$FUNAMBOL_HOME/tools/jre-1.5.0/jre
else
if [ ! -f "$JAVA_HOME/bin/java" ]; then
export JAVA_HOME=$FUNAMBOL_HOME/tools/jre-1.5.0/jre
fi
fi

if [ -z "$JAVA_HOME" ]; then
echo “Please, set JAVA_HOME before running this script.”
exit 1
fi

if [ ! -f "$JAVA_HOME/bin/java" ]
then
echo “Please set JAVA_HOME to the path of a valid jre.”
exit;
fi

export J2EE_HOME=${FUNAMBOL_HOME}/tools/tomcat
export CATALINA_HOME=${FUNAMBOL_HOME}/tools/tomcat

cd ${FUNAMBOL_HOME}

export LANG=en_US.utf-8

cd ${J2EE_HOME}/bin

case $1 in
start)

# Run DS Server
#
sh $FUNAMBOL_HOME/bin/funambol-server start > /dev/null
;;
stop)

# Shutdown Tomcat
#
sh $FUNAMBOL_HOME/bin/funambol-server stop > /dev/null
;;
*)
echo “usage: $0 [start|stop]”
;;
esac

Now we should see Web Demo client on http://yourserver.name:8080/ (admin/sa, guest/guest) and can synchronize a cellphone with following parameters:
Server name: http://yourserver.name:8080/funambol/ds
Username: guest
Password: guest
Sync what: Contacts, Calendar, Tasks, Notes (as needed)
Databases names:
Contacts: card
Calendar: event
Tasks: task
Notes: note

Get Google Calendar PHP SDK:
git clone -b v1-master https://github.com/google/google-api-php-client.git

Here is little changed quick start example of getting 10 future events from default calendar (read this instruction). Added import data to funambol database.
Before using this script we should create an application with appropriate scope and place client_secret.json file to our directory.
<?
$db_server_name = "localhost";
$db_username = "user";
$db_password = "password";
$db_name = "funambol";

$conn = new mysqli($db_server_name, $db_username, $db_password, $db_name);
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}
$conn->query("SET NAMES 'utf8'");

function add_event($dstart, $dend, $subject, $body, $gid, $all_day) {
  global $conn;
  $sql = "SELECT * FROM fnbl_pim_calendar WHERE gid='".$gid."'";
  $result = $conn->query($sql);
  if ($result->num_rows > 0) {
    //update
    $sql = "UPDATE fnbl_pim_calendar
      SET
        userid = 'guest',
        categories = 'MEETING',
        last_update = '".time()."000',
        status = 'N',
        type = 1,
        rec_type = -1,
        all_day = '".$all_day."',
        dstart = '".$dstart."',
        dend = '".$dend."',
        subject = '".$subject."',
        body = '".$body."'
      WHERE gid = '".$gid."'";
    $result = $conn->query($sql);
  }
  else {
    //create
    $sql = "INSERT INTO fnbl_pim_calendar
      SET
        userid = 'guest',
        categories = 'MEETING',
        last_update = '".time()."000',
        status = 'N',
        type = 1,
        rec_type = -1,
        all_day = '".$all_day."',
        dstart = '".$dstart."',
        dend = '".$dend."',
        subject = '".$subject."',
        body = '".$body."',
        gid = '".$gid."'";
    if(!$result = $conn->query($sql))
      printf("Errormessage: %s\n", $conn->error);
  }
}

set_include_path(get_include_path() . PATH_SEPARATOR . './google-api-php-client/src');

require_once './google-api-php-client/src/Google/autoload.php';


define('APPLICATION_NAME', 'Google Calendar API PHP Quickstart');
define('CREDENTIALS_PATH', './calendar-php-quickstart.json');
define('CLIENT_SECRET_PATH', './client_secret.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-php-quickstart.json
define('SCOPES', implode(' ', array(
  Google_Service_Calendar::CALENDAR_READONLY)
));

if (php_sapi_name() != 'cli') {
  throw new Exception('This application must be run on the command line.');
}

/**
* Returns an authorized API client.
* @return Google_Client the authorized client object
*/
function getClient() {
  $client = new Google_Client();
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES);
  $client->setAuthConfigFile(CLIENT_SECRET_PATH);
  $client->setAccessType('offline');

  // Load previously authorized credentials from a file.
  $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
  if (file_exists($credentialsPath)) {
    $accessToken = file_get_contents($credentialsPath);
  } else {
    // Request authorization from the user.
    $authUrl = $client->createAuthUrl();
    printf("Open the following link in your browser:\n%s\n", $authUrl);
    print 'Enter verification code: ';
    $authCode = trim(fgets(STDIN));

    // Exchange authorization code for an access token.
    $accessToken = $client->authenticate($authCode);

    // Store the credentials to disk.
    if(!file_exists(dirname($credentialsPath))) {
      mkdir(dirname($credentialsPath), 0700, true);
    }
    file_put_contents($credentialsPath, $accessToken);
    printf("Credentials saved to %s\n", $credentialsPath);
  }
  $client->setAccessToken($accessToken);

  // Refresh the token if it's expired.
  if ($client->isAccessTokenExpired()) {
    $client->refreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, $client->getAccessToken());
  }
  return $client;
}

/**
* Expands the home directory alias '~' to the full path.
* @param string $path the path to expand.
* @return string the expanded path.
*/
function expandHomeDirectory($path) {
  $homeDirectory = getenv('HOME');
  if (empty($homeDirectory)) {
    $homeDirectory = getenv("HOMEDRIVE") . getenv("HOMEPATH");
  }
  return str_replace('~', realpath($homeDirectory), $path);
}

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Calendar($client);

// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
  'maxResults' => 10,
  'orderBy' => 'startTime',
  'singleEvents' => TRUE,
  'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);

if (count($results->getItems()) == 0) {
  print "No upcoming events found.\n";
} else {
  print "Upcoming events:\n";
  foreach ($results->getItems() as $event) {
  $start_date = $event->start->date; //The date, in the format "yyyy-mm-dd", if this is an all-day event.
  $end_date = $event->end->date;
  $start_time = $end_time = "";
  $all_day = 1;
    if($event->start->dateTime) {
    $all_day = 0;
    $start = explode("T",$event->start->dateTime);
    $start_date = $start[0];
    $start_time = explode("+", $start[1]);
    $start_time = $start_time[0];
  }
    if($event->end->dateTime) {
    $end = explode("T",$event->end->dateTime);
    $end_date = $end[0];
    $end_time = explode("+", $end[1]);
    $end_time = $end_time[0];
  }
  if(!$end_date) $end_date = $start_date;
  
  $dstart = $start_date." ".$start_time;
  $dend = $end_date." ".$end_time;
  $subject = $event->getSummary();
  $body = $event->getDescription() ? $event->getDescription() : " ";
  $gid = $event->getId();
  //echo $dstart, $dend, $subject, $body, $gid, "\n";
      add_event($dstart, $dend, $subject, $body, $gid, $all_day);
  }
}
?>

After executing the script we can see added events in Funambol web interface and sync it to our phone.
adm, PHP
Highlight searched substring with php (23.06.2016)
Simple text highlighter on PHP, useful to mark search results.

$search = $_GET["search"]; //exists check ommited
$text = "Content in which to search here";

//i modifier to ignore case, u for utf-8 (cyrillic supported)
$search ? preg_replace("/".($search)."/iu", '<i>\0</i>' , $text) : $text;
PHP
Sorting any structure in PHP (03.02.2016)
With this example we can sort any kind of data - strings, arrays, objects etc. just changing required atribute in strcmp call.

PHP
function cmp($a, $b)
{
    return strcmp($a->created, $b->created);
}
usort($arr, "cmp");
PHP
Наброски по UMI CMS (20.11.2014)
XSLT-шаблоны:

Верстка должна быть XML-валидной!
Дебаг включается в config.ini:
[debug]
enabled = "1"
show-backtrace = "1"

Вывести контент в базовом шаблоне (<xsl:template match="/">):
<xsl:apply-templates select="result" />

Шаблон вывода этого контента, записывается или подключается после закрытия базового шаблона:

<xsl:template match="result[@module = 'content'][@method = 'content']">
  <h1>
    <xsl:value-of select=".//property[@name = 'h1']/value" />
  </h1>
  <div id="text">
    <xsl:value-of select=".//property[@name = 'content']/value" disable-output-escaping="yes" />
  </div>
</xsl:template>

Вызов макроса:

<xsl:value-of select="document('udata://custom/getChildren/')" disable-output-escaping="yes" />

макросы предлагается записывать в /classes/modules/custom.php

Список ссылок на дочерние страницы:

public function getChildren(){
  $current_page_id = cmsController::getInstance()->getCurrentElementId();
  $hierarchy = umiHierarchy::getInstance();
  $childs = $hierarchy->getChilds($current_page_id);
  $res = "";
  foreach ($childs as $child_id=>$value) {
    $page = $hierarchy->getElement($child_id);
    $title = $page->name;
    $path = $hierarchy->getPathById($child_id);
    $res.= "<li class='child'><a href='".$path."'>".$title."</a></li>";
  }
  if($res!="") $res = "<ul class='child_list'>".$res."</ul>";
  return $res;  
}

Пример по XSLT-макросам
PHP, CMS
Постинг через Facebook API v3 (18.11.2014)
Использую старую версию Facebook PHP SDK (v.3.2.3), поскольку для четверки нужен имеющийся не везде PHP 5.4.
Авторизация:
<?
require 'facebook-php-sdk/src/facebook.php';

$facebook = new Facebook(array(
  'appId'  => '$appId',
  'secret' => '$secret',
));

// Get User ID
$user = $facebook->getUser();
Костыль со stackoverflow, перенаправляющий нас на авторизацию, если она не подхватилась:
if ($user <> '0' && $user <> '') { /*if valid user id i.e. neither 0 nor blank nor null*/
  try {
  // Proceed knowing you have a logged in user who's authenticated.
    $user_profile = $facebook->api('/me');
  } catch (FacebookApiException $e) { /*sometimes it shows user id even if user in not logged in and it results in Oauth exception. In this case we will set it back to 0.*/
    error_log($e);
    $user = '0';
  }
}
else {/*If user id isn't present just redirect it to login url*/
  header("Location:{$facebook->getLoginUrl(array('req_perms' => 'email,offline_access'))}");
}
Попытаемся запостить сообщение на стену группы:
$facebook->api('/$group_id/feed/', 'post', array(
    'message' => 'I want to display this message on my wall',
  'link' => 'http://kodilo.ru',
  'picture' => 'http://images.boomsbeat.com/data/images/full/1893/facebook-jpg.jpg',
  'name' => 'The name of the link',
  'caption' => 'Caption of the link',
  'description' => 'Description of the link'
));
?>

Facebook PHP SDK
Решение проблемы с user=0
PHP, API
Постинг через API vk.com (13.11.2014)
Авторизация для JS-приложений (будут работать с разных ip и без редиректа токена):
https://oauth.vk.com/authorize?client_id=APP_ID&redirect_uri=https://oauth.vk.com/blank.html
&response_type=token&scope=friends,wall,offline&v=5.26
Параметр offline дает нам "вечный" токен до смены авторизовавшим его пользователем пароля. Токен будет получен в hash-части url.

Пример вызова метода:
https://api.vk.com/method/wall.post?owner_id=-PUBLIC_ID&access_token=TOKEN&message=MESSAGE&v=5.26

PHP и другие серверы: метод с получением code, затем token - херня и, хоть он до сих пор опубликован в документации, не работает. Токен все равно надо получать через браузер, как в примере выше.
$query = file_get_contents("https://api.vk.com/method/wall.post?owner_id=$public_id&message=Тест&v=5.26&access_token=$token")
JavaScript, PHP, API
Отключаем снятие ресурсов с публикации в modx revo (11.11.2014)
По умолчанию в modx при достижении даты снятия с публикации у ресурса помимо галки "опубликованности" (published) обнуляются также дата публикации (publishedon), дата автоматической публикации (pub_date) и дата снятия с публикации (unpub_date), что не очень удобно, т.к. полезно знать даты, когда ресурс был опубликован, даже когда он более не актуален. Примером может быть размещенный на сайте календарь - нам могут быть интересны уже прошедшие события, а плодить новые поля для указания дат, на мой взгляд, излишне.
Проверка наступления unpub_date производится в двух местах:
при ручном сохранении материала - в файле /core/model/modx/processors/resource/update.class.php, комментируем следующие строки:
public function setUnPublishDate() {
  ...
  /*$this->setProperty('published',0);
  $this->setProperty('unpub_date',0);
  $this->setProperty('pub_date',0);
  $this->setProperty('publishedon',0);*/
  ...
а также в менеджере кэша: /core/model/modx/modcachemanager.class.php:
public function autoPublish(array $options = array()) {
  ...
  //$publishingResults['unpublished']= $this->modx->exec("UPDATE $tblResource SET published=0, publishedon=0, pub_date=0, unpub_date=0 WHERE unpub_date IS NOT NULL AND unpub_date < {$timeNow} AND unpub_date > 0");
  ...
Modx, CMS, PHP
Простая пагинация для таблички (05.04.2013)
$p=htmlspecialchars($_GET["p"], ENT_QUOTES);
$num=30;
if (!!$p) $start=$p*$num;
else $start=0;
$count = mysql_fetch_row(mysql_query("SELECT COUNT(*) FROM table"));
echo "Страница № ";
for ($i=0;$i<$count[0]/$num;$i++) {
  echo "<a href=/?p=".$i.">".$i."</a> / ";
}
$query = mysql_query("SELECT fields...
  FROM table
  LIMIT ".$start.",".$num
);
PHP
Пагинация (20.10.2012)
Когда постов становится много, нужна разбивка по страницам.
Получаем номер страницы в GET:

  isset($_GET[page]) ? $page=$_GET[page] : $page=0;
  
Считаем количество строк (в моем случае - просто вся таблица):

  $row=mysql_fetch_row(mysql_query("SELECT count(*) FROM Table"));
  $count = $row[0];

Количество постов на страницу и вычисления границ выборки:

  $posts_per_page = 5;
  $page_start = $page*$posts_per_page;

В конец mysql-запроса добавить:

  LIMIT $page_start,$posts_per_page

Вывод ссылок next-prev:

  if (($page+1)*5<$count) {?>
    <a href="/page<?=$page+1?>/">Prev page</a>
  <?
  }
  if ($page>0) {?>
    <a style="float: right;" href="/page<?=$page-1?>/">Next page</a>
PHP
PHP-авторизация (18.10.2012)
Какой же сайт может существовать без супер-секретной авторизации. Для местных нужд я написал следующую функцию. Для многопользовательского режима $login и $password будут итерироваться исходя из количества строк в таблице базы с пользователями, разумеется. Ну и вместо пароля во всех случаях желательно использовать хеш.

function auth() {
  $login="SuperVasya";
  $password="MegaPassword";
  if (isset($_POST[logout])) {
    unset($_SESSION[login]);
    $output = "Bye";
  }
  if (isset($_SESSION[login])) {
    $output = $_SESSION[login].'
    <form class="login" method="POST">
      <input type="hidden" name="logout" value="'.$_SESSION[login].'">
      <input type="submit" value="Выход">
    </form>';
  }
  else {
    if (isset($_POST[login])) {
      if ($_POST[login]!=$login) {
        $output = "No such user";
      }
      else if ($_POST[password]!=$password) {
          $output = "Wrong password";
      }
      else {
        $_SESSION[login] = $_POST[login];
        $output = auth();
      }
    }
    else {
      $output = '
      <form class="login" method="POST">
      <input type="text" name="login">
      <input type="password" name="password">
      <input type="submit" value="Вход">
      </form>';
    }
  }
    return $output;
}

Перед выводом контента я делаю $output = auth(), далее выводим $output в нужном месте. Проверка на "хорошего парня" определяется существованием $_SESSION[login]:
if (isset($_SESSION[login])) echo 'Top secret';
PHP
JavaScript (13)
PHP (11)
Brainfuck (8)
adm (8)
Joomla (4)
Canvas (3)
answers (2)
API (2)
CMS (2)
Modx (2)
jQuery (1)
Ajax (1)
SQL (1)
Shell (1)
batch (1)
10-6