You are here

vkxp.module in VK CrossPoster 7

File

vkxp.module
View source
<?php

/**
 * @file
 *
 */

/**
 * Constant definition.
 */

// Constants for access token process.
define('VKXP_ACCESS_TOKEN_URI', 'https://oauth.vk.com/access_token');
define('VKXP_ACCESS_TOKEN_REDIRECT_URI', 'vkxp');

// Constants for authorize process.
define('VKXP_AUTHORIZE_URI', 'http://oauth.vk.com/authorize');
define('VKXP_AUTHORIZE_SCOPE', 'wall,groups,photos,offline');
define('VKXP_AUTHORIZE_REDIRECT_URI', 'vkxp');
define('VKXP_AUTHORIZE_RESPONSE_TYPE', 'code');
define('VKXP_AUTHORIZE_DISPLAY', 'page');

// Constants for API calls.
define('VKXP_API_REQUEST_URI', 'https://api.vk.com/method');

/**
 * Implements hook_help().
 */
function vkxp_help($path) {
  switch ($path) {
    case 'admin/config/services/vkxp':
      return t('Vkontakte CrossPoster module allows to post nodes automatically to social network vk.com.');
    case 'admin/help#vkxp':
      $output = '';
      $output .= '<p>' . t('Vkontakte CrossPoster module allows users to post nodes automatically to social network http://vk.com.') . '</p>';
      $output .= '<p>' . t('It requires creating web site application at http://vk.com/editapp?act=create') . '</p>';
      $output .= '<p>' . t('After creating application you should go to module settings page and put there secret code and application ID.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_menu().
 */
function vkxp_menu() {
  $items['admin/config/services/vkxp'] = array(
    'title' => 'VKontakte CrossPoster',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vkxp_admin_main_settings',
    ),
    'access arguments' => array(
      'administer vkontakte crossposter',
    ),
    'file' => 'vkxp.admin.inc',
  );
  $items['admin/config/services/vkxp/main'] = array(
    'title' => 'Main settings',
    'file' => 'vkxp.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['admin/config/services/vkxp/node'] = array(
    'title' => 'Node settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vkxp_admin_node_settings',
    ),
    'access arguments' => array(
      'administer vkontakte crossposter',
    ),
    'file' => 'vkxp.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/config/services/vkxp/images'] = array(
    'title' => 'Images settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vkxp_admin_images_settings',
    ),
    'access arguments' => array(
      'administer vkontakte crossposter',
    ),
    'file' => 'vkxp.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );

  // This page recieves authorization result from vk.com.
  $items['vkxp'] = array(
    'page callback' => 'vkxp_authorize',
    'access callback' => TRUE,
    'file' => 'vkxp.pages.inc',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function vkxp_permission() {
  return array(
    'administer vkontakte crossposter' => array(
      'title' => t('Administer vkontakte crossposter'),
      'description' => t('Change settings of vkxp module behavior.'),
    ),
    'post to vkontakte' => array(
      'title' => t('Post nodes to vk.com'),
      'description' => t('Allows user to post nodes automatically to vk.com.'),
    ),
  );
}

/**
 * Implements hook_form_alter().
 */
function vkxp_form_alter(&$form, &$form_state, $form_id) {

  // Get node types that could be crossposted.
  $enabled_node_types = variable_get('vkxp_node_types', array());
  $selected_types = array_filter($enabled_node_types);
  foreach ($selected_types as $node_type) {
    if ($form_id == $node_type . '_node_form') {
      _vkxp_process_node_form($form);
    }
  }
}

/**
 * Add vkxp fieldset to node forms.
 *
 * @param $form
 *   Node add/edit form.
 */
function _vkxp_process_node_form(&$form) {

  // Change node form only if user has access to crosspost nodes.
  if (user_access('post to vkontakte')) {
    $form['vkxp'] = array(
      '#type' => 'fieldset',
      '#title' => t('VKontakte CrossPoster'),
      '#group' => 'additional_settings',
      '#weight' => -10,
    );
    $form['vkxp']['vkxp_post_this_node'] = array(
      '#type' => 'checkbox',
      '#title' => t('Post this node to vk.com'),
      '#default_value' => variable_get('vkxp_enabled_default', 0),
      '#description' => t('After you submit this node it will be posted to http://vk.com.'),
    );

    // Disable crosspost if cURL library is not installed on a server.
    if (!function_exists('curl_init')) {
      $form['vkxp']['vkxp_post_this_node']['#disabled'] = TRUE;
      $form['vkxp']['vkxp_post_this_node']['#value'] = 0;
      $form['vkxp']['vkxp_post_this_node']['#description'] = t("You can't crosspost nodes until cURL library is not installed on your server.");
    }
  }
}

/**
 * Implements hook_node_insert().
 */
function vkxp_node_insert($node) {

  // Post node to vk.com.
  _vkxp_process_node($node, 'insert');
}

/**
 * Implements hook_node_update().
 */
function vkxp_node_update($node) {

  // Post node to vk.com.
  _vkxp_process_node($node, 'update');
}

/**
 * Process node and send it to vk.com if needed.
 *
 * @param $node
 *   Node object during insert/update.
 * @param $op
 *  Current node operation (insert or update).
 */
function _vkxp_process_node($node, $op) {

  // Get node types that could be crossposted.
  $enabled_node_types = variable_get('vkxp_node_types', array());
  $selected_types = array_filter($enabled_node_types);

  // If current node is in selected types list - crosspost it.
  if (in_array($node->type, $selected_types)) {

    // Collect data and check access to crosspost nodes.
    $access_token = variable_get('vkxp_access_token', '');
    $user_access = user_access('post to vkontakte');
    $post_node = FALSE;
    if (isset($node->vkxp_post_this_node)) {
      $post_node = $node->vkxp_post_this_node;
    }

    // Check requiered data to post.
    if ($access_token && $user_access && $post_node) {

      // Clear cached data if user wants to add link to this page.
      // If do not flush page cache, vkontakte may not post this node due to unaccessable node url.
      $add_link_to_node = variable_get('vkxp_add_link', 0);
      $cache_disabled = variable_get('cache', 0) ? FALSE : TRUE;
      if ($add_link_to_node && !$cache_disabled && $op == 'insert') {
        cache_clear_all(NULL, 'cache_page');
      }

      // Get absolute node link.
      $url = url('node/' . $node->nid, array(
        'absolute' => TRUE,
      ));

      // Get message from node.
      $post_object = variable_get('vkxp_post_object', 'body');
      if ($post_object == 'body') {
        $body = array_shift($node->body);
        $message = trim(strip_tags($body[0]['value']));
      }
      elseif ($post_object == 'title') {
        $message = trim(check_plain($node->title));
      }
      else {
        $body = array_shift($node->body);
        $message = trim(check_plain($node->title)) . "\n\n" . trim(strip_tags($body[0]['value']));
      }

      // Trim message if needed.
      $cut_message = variable_get('vkxp_cut_message', 1);
      if ($cut_message) {
        $length = variable_get('vkxp_cut_message_length', 255);
        if (drupal_strlen($message) > $length) {
          $message = drupal_substr($message, 0, $length - 3) . '...';
        }
      }

      // Decode special symbols.
      $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
      $message = htmlspecialchars_decode($message);

      // Post node to vk.com.
      $images = _vkxp_get_node_images($node);
      $image_ids = '';
      if ($images) {
        $upload_url = _vkxp_get_upload_server();
        $image_ids = _vkxp_upload_images($upload_url, $images);
      }
      _vkxp_post_to_wall($message, $url, $image_ids);
    }
  }
}

/**
 * Function makes http query to vk.com.
 * Allows using hook_vkxp_query_alter() for altering query params.
 */
function vkxp_query($method, $params, $request_url = VKXP_API_REQUEST_URI) {

  // Collect query data.
  $query = array();
  $query['method'] = $method;
  $query['params'] = $params;
  $query['request_url'] = $request_url;
  drupal_alter('vkxp_query', $query);

  // cURL request to vk.com.
  // @TODO: try to change cURL support to drupal_http_request().
  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, $query['request_url'] . '/' . $query['method']);
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $query['params']);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  $result = curl_exec($curl);
  curl_close($curl);

  // Return request result.
  return drupal_json_decode($result);
}

/**
 * Get images from selected imagefield.
 *
 * @param $node
 *   Node object that should be crossposted.
 *
 * @return array
 *   Array with images for uploading.
 */
function _vkxp_get_node_images($node) {
  $images = array();

  // Load image amount that should be sent to vk.com.
  $image_amount = variable_get('vkxp_' . $node->type . '_image_amount', 0);
  if ($image_amount) {

    // Get node field name that contains image.
    $field = variable_get('vkxp_' . $node->type . '_image_field', '');

    // Try to get images from node object.
    $i = 0;
    $items = field_get_items('node', $node, $field);
    if (!empty($items) && is_array($items)) {
      foreach ($items as $image) {
        if (isset($image['fid'])) {

          // If user set image limit we should check get only selected amount of images.
          if ($i++ == $image_amount) {
            break;
          }

          // Get real image path.
          $uri = file_load($image['fid'])->uri;
          $images[] = '@' . drupal_realpath($uri);
        }
      }
    }
  }
  return $images;
}

/**
 * Makes http query to api server to get upload uri.
 *
 * @return string|bool
 *  Upload url on success or FALSE on failure.
 */
function _vkxp_get_upload_server() {
  $params = array();
  if (variable_get('vkxp_wall_owner', 'group') == 'group') {
    $params['gid'] = variable_get('vkxp_group_id', '');
  }
  else {
    $params['uid'] = variable_get('vkxp_group_id', '');
  }
  $params['access_token'] = variable_get('vkxp_access_token', '');
  $result = vkxp_query('photos.getWallUploadServer', $params);
  if ($result['response']['upload_url']) {
    return $result['response']['upload_url'];
  }
  elseif ($result['error']) {
    _vkxp_watchdog(array(
      'text' => t('Unable to recieve upload server. Error: !error', array(
        '!error' => $result['error']['error_msg'],
      )),
      'severity' => 'error',
    ));
  }
  return FALSE;
}

/**
 * Upload and save images to vk server.
 *
 * @param  $upload_url
 *   Url of upload server.
 * @param  $images
 *   Array of images to upload.
 *
 * @return string
 *   Uploaded image IDs separated by comma.
 *   Example: photo312312_3123123,photo312312_3123124.
 */
function _vkxp_upload_images($upload_url, $images) {

  // Array with saved image IDs.
  $image_ids = array();
  foreach ($images as $image) {

    // Upload photo.
    $upload_result = vkxp_query('', array(
      'photo' => $image,
    ), $upload_url);

    // If photo was uploaded it should be saved.
    if ($upload_result['server'] && $upload_result['photo'] && $upload_result['hash']) {
      $params = array();
      $params['access_token'] = variable_get('vkxp_access_token', '');
      $params['server'] = $upload_result['server'];
      $params['photo'] = $upload_result['photo'];
      $params['hash'] = $upload_result['hash'];
      if (variable_get('vkxp_wall_owner', 'group') == 'group') {
        $params['gid'] = variable_get('vkxp_group_id', '');
      }
      else {
        $params['uid'] = variable_get('vkxp_group_id', '');
      }

      // Upload query to vk.com.
      $save_result = vkxp_query('photos.saveWallPhoto', $params);

      // If image was successfully saved it returns photo ID in format 'photoXXXXXXX_XXXXXXX'.
      if (isset($save_result['response'][0]['id'])) {
        $image_ids[] = $save_result['response'][0]['id'];
      }
    }
  }
  return !empty($image_ids) ? implode(',', $image_ids) : '';
}

/**
 * Post node message with uploaded images to wall.
 *
 * @param  $message
 *   Text to post.
 * @param  $images
 *   String with photo IDs to post.
 * @param  $url
 *   Absolute link to posted node.
 *
 * @return array
 *   Server response.
 */
function _vkxp_post_to_wall($message, $url, $images = '') {
  $params = array();
  $params['from_group'] = variable_get('vkxp_official', 1);
  if (variable_get('vkxp_wall_owner', 'group') == 'group') {
    $params['owner_id'] = '-' . variable_get('vkxp_group_id', '');
  }
  else {
    $params['owner_id'] = variable_get('vkxp_group_id', '');
  }
  $params['message'] = $message;
  $params['attachments'] = $images;
  if (variable_get('vkxp_add_link', 0)) {
    if ($images) {
      $params['attachments'] .= ',' . $url;
    }
    else {
      $params['attachments'] = $url;
    }
  }
  $params['access_token'] = variable_get('vkxp_access_token');

  // Send query to vk.com and return result.
  return vkxp_query('wall.post', $params);
}

/**
 * Log messages and print it on the screen.
 *
 * @param $message
 *   Array with message and it severity.
 *
 * @param $link
 *   Link to view node.
 */
function _vkxp_watchdog($message, $link = NULL) {

  // Set message about event.
  drupal_set_message($message['text'], $message['severity']);

  // Log event into watchdog.
  if ($message['severity'] == 'status') {
    $severity = WATCHDOG_INFO;
  }
  elseif ($message['severity'] == 'warning') {
    $severity = WATCHDOG_WARNING;
  }
  else {
    $severity = WATCHDOG_ERROR;
  }
  watchdog('vkxp', $message['text'], array(), $severity, $link);
}

Functions

Namesort descending Description
vkxp_form_alter Implements hook_form_alter().
vkxp_help Implements hook_help().
vkxp_menu Implements hook_menu().
vkxp_node_insert Implements hook_node_insert().
vkxp_node_update Implements hook_node_update().
vkxp_permission Implements hook_permission().
vkxp_query Function makes http query to vk.com. Allows using hook_vkxp_query_alter() for altering query params.
_vkxp_get_node_images Get images from selected imagefield.
_vkxp_get_upload_server Makes http query to api server to get upload uri.
_vkxp_post_to_wall Post node message with uploaded images to wall.
_vkxp_process_node Process node and send it to vk.com if needed.
_vkxp_process_node_form Add vkxp fieldset to node forms.
_vkxp_upload_images Upload and save images to vk server.
_vkxp_watchdog Log messages and print it on the screen.

Constants