You are here

vkxp.module in VK CrossPoster 7.2

Same filename and directory in other branches
  1. 8 vkxp.module
  2. 6.3 vkxp.module
  3. 6 vkxp.module
  4. 6.2 vkxp.module
  5. 7 vkxp.module

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', 'http://oauth.vk.com/blank.html');

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

// 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.');
    case 'admin/help#vkxp':
      $output = '';
      $output .= '<p>' . t('Vkontakte CrossPoster module allows users to post nodes automatically to social network VK.') . '</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 the module settings page and copy there Application ID and Secret code.') . '</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',
  );

  // Module settings page.
  $items['admin/config/services/vkxp/settings'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vkxp_admin_main_settings',
    ),
    'access arguments' => array(
      'administer vkontakte crossposter',
    ),
    'file' => 'vkxp.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 1,
  );

  // Page for building access token.
  $items['admin/config/services/vkxp/access_token'] = array(
    'title' => 'Recieve access token',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vkxp_admin_access_token',
    ),
    'access arguments' => array(
      'administer vkontakte crossposter',
    ),
    'file' => 'vkxp.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
  if (variable_get('vkxp_add_post_tab', FALSE)) {
    $items['node/%/post_to_vk'] = array(
      'title' => 'Post to VK.com',
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'vkxp_post_tab_form',
      ),
      'access arguments' => array(
        'post to vkontakte',
      ),
      'file' => 'vkxp.forms.inc',
      'type' => MENU_LOCAL_TASK,
      'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    );
  }
  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'),
      'description' => t('Allow user to post nodes to VK.'),
    ),
  );
}

/**
 * Implements hook_form_FORM_ID_alter().
 * Add module settings to the node settings form.
 */
function vkxp_form_node_type_form_alter(&$form, &$form_state) {
  form_load_include($form_state, 'forms.inc', 'vkxp');
  _vkxp_process_node_settings_form($form);
}

/**
 * Implements hook_form_FORM_ID_alter().
 * Alters node add/edit form.
 */
function vkxp_form_node_form_alter(&$form, &$form_state) {

  // Do not process node form if it is not contains node type.
  if (empty($form['#node']->type)) {
    return;
  }

  // Check node type and user access to see whether we should process a node form.
  $type_enabled = variable_get('vkxp_node_enabled_' . $form['#node']->type);
  $user_access = user_access('post to vkontakte');

  // If node type matches all requirements we have to add new fields to form.
  if ($type_enabled && $user_access) {
    form_load_include($form_state, 'forms.inc', 'vkxp');
    _vkxp_process_node_form($form);
  }
}

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

  // Post node to VK.
  _vkxp_process_node($node);
}

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

  // Post node to VK.
  _vkxp_process_node($node);
}

/**
 * Implements hook_node_presave().
 */
function vkxp_node_presave($node) {

  // Get all flags to see if node could be crossposted.
  $vkxp_enabled = variable_get('vkxp_node_enabled_' . $node->type);
  $access_token = variable_get('vkxp_access_token');
  $user_access = user_access('post to vkontakte');
  $post_node = isset($node->vkxp_post_this_node) ? $node->vkxp_post_this_node : FALSE;
  if ($vkxp_enabled && $access_token && $user_access && $post_node) {
    $node->vkxp_sent = TRUE;
  }
}

/**
 * Implements hook_node_type_delete().
 */
function vkxp_node_type_delete($info) {
  $vars = array(
    'vkxp_node_enabled_',
    'vkxp_node_enabled_default_',
    'vkxp_node_message_field_',
    'vkxp_node_message_length_',
    'vkxp_node_image_field_',
    'vkxp_node_image_field_style_',
    'vkxp_node_image_limit_',
    'vkxp_node_enabled_default_',
  );
  foreach ($vars as $var) {
    variable_del($var . $info->type);
  }
}

/**
 * Process node and send it to VK if needed.
 *
 * @param $node
 *   Node object during insert/update.
 */
function _vkxp_process_node($node, $force = FALSE) {

  // Get all flags to see if node could be crossposted.
  $vkxp_enabled = variable_get('vkxp_node_enabled_' . $node->type);
  $access_token = variable_get('vkxp_access_token');
  $user_access = user_access('post to vkontakte');
  $post_node = isset($node->vkxp_post_this_node) ? $node->vkxp_post_this_node : FALSE;
  if ($force) {
    $post_node = TRUE;
  }

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

    // Get node data that will be crossposted.
    $message = _vkxp_get_node_message($node);
    $images = _vkxp_get_node_images($node);
    $url = url('node/' . $node->nid, array(
      'absolute' => TRUE,
    ));

    // Post node to VK.
    _vkxp_post_to_wall($message, $images, $url);
  }
}

/**
 * Get images from node.
 *
 * @param $node
 *   Node object that should be crossposted.
 *
 * @return array
 *   Array with uploaded images.
 */
function _vkxp_get_node_images($node) {
  $image_ids = '';

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

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

    // Get image style if exists.
    $image_style = variable_get('vkxp_node_image_field_style_' . $node->type, FALSE);

    // Try to get images from node object.
    $i = 0;
    $items = field_get_items('node', $node, $field);
    if (!empty($items) && is_array($items)) {
      $images = array();
      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;
          }
          $file = file_load($image['fid']);
          if ($image_style) {
            $uri = vkxp_get_image_style_uri($image_style, $file);
          }
          else {
            $uri = $file->uri;
          }

          // Get real image path.
          $uri = drupal_realpath($uri);

          // PHP version > 5.5.
          if (function_exists('curl_file_create')) {
            $images[] = curl_file_create($uri);
          }
          else {
            $images[] = '@' . $uri;
          }
        }
      }
    }

    // Upload images to vk server.
    if (!empty($images)) {
      $upload_url = _vkxp_get_upload_server();
      $image_ids = _vkxp_upload_images($upload_url, $images);
    }
  }
  return $image_ids;
}

/**
 * Get message text from node.
 *
 * @param $node
 *   Node object that should be crossposted.
 *
 * @return string
 *   Message text.
 */
function _vkxp_get_node_message($node) {

  // Get message source.
  $message_field = variable_get('vkxp_node_message_field_' . $node->type, '[node:title]');
  $message = strip_tags(token_replace($message_field, array(
    'node' => $node,
  )));

  // Trim message if needed.
  $message_length = variable_get('vkxp_node_message_length_' . $node->type, 255);
  if (!empty($message_length) && drupal_strlen($message) > $message_length) {
    $message = drupal_substr($message, 0, $message_length - 3) . '...';
  }

  // Add tags as hashtags to the post.
  $tags_field = variable_get('vkxp_node_hashtag_field_' . $node->type, 0);
  if (!empty($tags_field)) {
    $tags_items = field_get_items('node', $node, $tags_field);
    if (!empty($tags_items)) {
      $message .= "\n\n";
      $hash_tags = array();
      $tags = array();
      foreach ($tags_items as $item) {

        //Sometimes name attribute is not added to the field value - loading it.
        if (empty($item['name'])) {
          $term = taxonomy_term_load($item['tid']);
          $tags[] = $term->name;
        }
        else {
          $tags[] = $item['name'];
        }
      }
      foreach ($tags as $item) {
        $hash_tags[] = '#' . str_replace(' ', '', $item);
      }
      $message .= implode(' ', $hash_tags);
    }
  }

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

/**
 * Function makes http query to VK.
 * 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.
  $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);
  $res_decoded = json_decode($result);

  // If we have errors in response - showing them to the site administrator.
  foreach ($res_decoded as $item) {
    if (!empty($item->error_code)) {
      _vkxp_watchdog(array(
        'text' => '[' . $item->error_code . '] :' . $item->error_msg,
        'severity' => 'error',
      ));
    }
  }
  curl_close($curl);

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

/**
 * Provides image style uri.
 *
 * If image does not exists it will create stylized image and return it uri.
 *
 * @param $file
 *  Image file object.
 * @param $style
 *  Requested image style machine name.
 */
function vkxp_get_image_style_uri($style, $file) {
  $file_uri = image_style_path($style, $file->uri);
  if (!file_exists($file_uri)) {
    if (!image_style_create_derivative($style, $file->uri, $file_uri)) {
      drupal_set_message(t('Failed to create stylized image'), 'error');
    }
  }
  return $file_uri;
}

/**
 * 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_owner_id', '');
  }
  else {
    $params['uid'] = variable_get('vkxp_owner_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 to vk server.
    $upload_result = vkxp_query('', array(
      'photo' => $image,
    ), $upload_url);

    // If photo was uploaded it should be saved.
    if (isset($upload_result['server']) && isset($upload_result['photo']) && isset($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'];

      // Get owner ID depends on its type.
      if (variable_get('vkxp_wall_owner', 'group') == 'group') {
        $params['gid'] = variable_get('vkxp_owner_id', '');
      }
      else {
        $params['uid'] = variable_get('vkxp_owner_id', '');
      }

      // Save uploaded images.
      $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, $images, $url) {
  $params = array();
  $params['from_group'] = variable_get('vkxp_official', TRUE);
  if (variable_get('vkxp_wall_owner', 'group') == 'group') {
    $params['owner_id'] = '-' . variable_get('vkxp_owner_id', '');
  }
  else {
    $params['owner_id'] = variable_get('vkxp_owner_id', '');
  }
  $params['message'] = $message;
  $params['attachments'] = $images;
  if (variable_get('vkxp_add_link', FALSE)) {
    $params['attachments'] .= !empty($images) ? ',' . $url : $url;
  }
  $params['access_token'] = variable_get('vkxp_access_token');

  // Send query to VK 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_node_form_alter Implements hook_form_FORM_ID_alter(). Alters node add/edit form.
vkxp_form_node_type_form_alter Implements hook_form_FORM_ID_alter(). Add module settings to the node settings form.
vkxp_get_image_style_uri Provides image style uri.
vkxp_help Implements hook_help().
vkxp_menu Implements hook_menu().
vkxp_node_insert Implements hook_node_insert().
vkxp_node_presave Implements hook_node_presave().
vkxp_node_type_delete Implements hook_node_type_delete().
vkxp_node_update Implements hook_node_update().
vkxp_permission Implements hook_permission().
vkxp_query Function makes http query to VK. Allows using hook_vkxp_query_alter() for altering query params.
_vkxp_get_node_images Get images from node.
_vkxp_get_node_message Get message text from node.
_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 if needed.
_vkxp_upload_images Upload and save images to vk server.
_vkxp_watchdog Log messages and print it on the screen.

Constants