HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux ip-172-31-4-197 6.8.0-1036-aws #38~22.04.1-Ubuntu SMP Fri Aug 22 15:44:33 UTC 2025 x86_64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/html/wordpress/wp-content/plugins/trinity-audio/inc/post-hashes.php
<?php
  /**
   * Post hashes update functionality.
   *
   * Functionality for generating post hashes that are required for player to playback audio.
   * Generating hashes consists from 3 parts:
   * 1. Get text from DB that are going to be played and get sha1 hashes
   *    - The format is an object, where key is postId and values if object which consists with the following feidls:
   *      - content
   *      - title + content
   *      - excerpt + content
   *      - title + excerpt + content
   * 2. Send that data as one request to Trinity service with private installkey in order to get final post hashes which will be used in player
   * 3. Write them into DB
   *
   * During each stage (calculating_hashes and writing_hashes) current stage is written into DB with total posts updated,
   * failed and current performance (ability to process posts per second). Later these numbers are used in post hashes batch functionality.
   *
   * Pay attention, that functionality is used by Post hashes bulk update, in case we update all posts hashes.
   * In case we update only 1 particular post - functionality here is used directly.
   */

  require_once __DIR__ . '/common.php';
  require_once __DIR__ . '/post-hashes-bulk-update.php';
  require_once __DIR__ . '/text.php';

  /**
   * Start posts hashes bulk update
   * @param array $post_ids posts ids to be processed
   * @return void
   */
  function trinity_ph_update_bulk_update(array $post_ids, $total_posts, $updated_posts, $batch_retry): int {
    $total_posts_to_process = count($post_ids);
    trinity_log("Bulk update - processing $total_posts_to_process posts...");

    // main function to process posts and get hashes
    return trinity_ph_update($post_ids, $total_posts, $updated_posts, $batch_retry, true);
  }

  /**
   * Main post hashes function that runs 3 phases like calculating, requesting and writing into DB
   * @param $post_ids
   * @return number
   */
  function trinity_ph_update($post_ids, $total_posts = 1, $updated_posts = 0, $batch_retry = 0, $is_bulk = false): int {
    $posts_amount = count($post_ids);
    trinity_log("Post hashes updating for $posts_amount post(s) ⚙️");

    // stage #1 - calculating hashes
    $calculated_hashes = trinity_ph_update_calculate_hashes($post_ids);

    // stage #2 - requesting hashes
    $requested_hashes = trinity_ph_update_requesting_hashes($calculated_hashes, $total_posts, $updated_posts, $batch_retry, $is_bulk);

    if ($requested_hashes === -1) return -1; // isStop

    if (!$requested_hashes) {
      trinity_log("Can't get hashes from server", '', '', TRINITY_AUDIO_ERROR_TYPES::error);
      return 0;
    }

    // stage #3 - writing hashes
    trinity_ph_update_writing_hashes($requested_hashes['hashes']);

    trinity_log("Post hashes updated for $posts_amount post(s) ✅");

    return 1; // OK
  }

  /**
   * First phase of post hashes - calculate hashes from posts texts
   * @param array $post_ids
   * @return array
   */
  function trinity_ph_update_calculate_hashes(array $post_ids): array {
    trinity_log('Post hashes update - calculation hashes...');

    $posts_total_amount   = sizeof($post_ids);
    $posts_success_amount = 0;
    $post_id_index        = 0;

    $whitelist_shortcodes = trinity_get_allowed_shortcodes();

    $hashes = [];

    while ($posts_total_amount > $post_id_index) {
      try {
        $post_id = $post_ids[$post_id_index];

        $title   = get_the_title($post_id);
        $content = get_post_field('post_content', $post_id);

        $result_text_title_content = trinity_get_clean_text($title, $content, $whitelist_shortcodes);

        $hashes[$post_id] = [
          TRINITY_AUDIO_POST_META_MAP[TRINITY_AUDIO_TITLE_CONTENT] => sha1($result_text_title_content)
        ];

        ++$post_id_index;
        ++$posts_success_amount;
      } catch (Exception $error) {
        trinity_log("Error while calculating hashes, post hash id: $post_ids[$post_id_index]", '', '', TRINITY_AUDIO_ERROR_TYPES::error);
      }
    }

    trinity_log('Post hashes update - calculation hashes done');

    return $hashes;
  }

  /**
   * Request final hashes from Trinity service endpoint
   * @param $hashes
   * @return null
   * @throws Exception
   */
  function trinity_ph_update_requesting_hashes($hashes, $total_posts, $updated_posts, $batch_retry, $is_bulk) {
    trinity_log('Post hashes update - requesting hashes...');

    $env_details = trinity_get_env_details();
    $installkey  = trinity_get_install_key();

    $post_data = [
      'hashes'        => $hashes,
      'totalPosts'    => $total_posts,
      'updatedPosts'  => $updated_posts,
      'batchRetry'    => $batch_retry,
      'isBulk'        => $is_bulk,
      'installkey'    => $installkey,
      'pluginVersion' => $env_details['plugin_version']
    ];

    $response = trinity_curl_post(
      [
        'post_data'       => gzencode(json_encode($post_data)), // compress with gzip, for 2k of posts - 450kb => 225kb
        'url'             => TRINITY_AUDIO_POST_HASH_URL_V2,
        'error_message'   => "Can't get hashes from server",
        'die'             => false,
        'throw_exception' => false,
        'http_args'       => [
          'headers' => [
            'Content-Encoding' => 'gzip',
            'Content-Type'     => 'application/json'
          ]
        ]
      ]
    );

    if (!$response) return trinity_ph_update_requesting_hashes_report_error('Can\'t POST to ' . TRINITY_AUDIO_POST_HASH_URL_V2, $post_data);
    if (isset($response['isStop']) && $is_bulk) return -1;
    if (!isset($response['hashes'])) return trinity_ph_update_requesting_hashes_report_error('Did not get hashes back!', $post_data);

    trinity_log('Post hashes update - requesting hashes done');

    return $response;
  }

  function trinity_ph_update_requesting_hashes_report_error($error_message, $post_data) {
    trinity_log($error_message, '', trinity_dump_object($post_data), TRINITY_AUDIO_ERROR_TYPES::error);
  }

  /**
   * Writing final post hashes into DB
   * @param $hashes
   * @return void
   */
  function trinity_ph_update_writing_hashes($hashes) {
    trinity_log('Post hashes update - writing hashes...');

    $hashes_amount = count($hashes);

    // calculate how many times we have to update state (in order to reflect on UI). Should be >= 1 < 10
    $to_update_times = round($hashes_amount / 10);
    if ($to_update_times < 1) $to_update_times = 1;

    $posts_success_amount = 0;
    foreach ($hashes as $key => $value) {
      ++$posts_success_amount;
      update_post_meta($key, 'trinity_audio_post_hash', $value); // we can't rely on return value false here, since it will return false when data was not change
    }

    trinity_log('Post hashes update - writing hashes done');
  }

  function trinity_ph_update_regenerate_tokens() {
    check_ajax_referer('regenerate_tokens_action', TRINITY_AUDIO_AJAX_NONCE_NAME);

    $post_id = sanitize_text_field(wp_unslash($_POST['post_id']));

    if (!trinity_ph_update([$post_id])) die(json_encode([], JSON_FORCE_OBJECT));

    header('Content-type: application/json');
    die(json_encode(trinity_ph_get_posthashes_for_post_id($post_id)));
  }

  function trinity_ph_get_posthashes_for_post_id($post_id) {
    return get_post_meta($post_id, TRINITY_AUDIO_POST_HASH, true);
  }

  function trinity_ph_update_save_post_callback($post_id, $post, $updated) {
    // Check if this isn't an auto save.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
      return;
    }

    // avoid doing something when post moved to Trash or was just created and in draft (before save)
    if ($post->post_type === 'revision' || $post->post_status === 'auto-draft') {
      return;
    }

    $is_enable = (int)isset($_POST[TRINITY_AUDIO_ENABLED]);

    // if it's a new post
    if (!$updated) {
      // in case we have enabled option to enable player on post API creation and have default new posts enabled - then do it
      if (trinity_get_enable_for_api() && trinity_get_new_posts_default()) {
        trinity_audio_enable_player_for_post_id($post_id, 1);
        trinity_ph_update([$post_id]);
      }

      return;
    }

    // Validate if this post which is being saved is one of supported types. If not, return.
    $post_types_supported = ['post'];
    $post_type            = get_post_type($post_id);
    if (!in_array($post_type, $post_types_supported)) {
      return;
    }

    // If nonce is valid then update post meta
    // If it's not valid then this is probably a quick or bulk edit request in which case we won't update the post meta
    if (isset($_POST[TRINITY_AUDIO_NONCE_NAME]) && wp_verify_nonce($_POST[TRINITY_AUDIO_NONCE_NAME], 'trinity-audio-metabox')) {
      trinity_audio_enable_player_for_post_id($post_id, $is_enable);

      // Update post source language
      update_post_meta($post_id, TRINITY_AUDIO_SOURCE_LANGUAGE, sanitize_text_field($_POST[TRINITY_AUDIO_SOURCE_LANGUAGE]));

      // Update post voice id
      update_post_meta($post_id, TRINITY_AUDIO_VOICE_ID, sanitize_text_field($_POST[TRINITY_AUDIO_VOICE_ID]));
    }

    trinity_ph_update([$post_id]);
  }

  function trinity_audio_enable_player_for_post_id($post_id, $is_enable) {
    update_post_meta($post_id, TRINITY_AUDIO_ENABLED, $is_enable);
  }

  /** Return post hash for postId
   * @param $post_id
   * @return mixed|void
   */
  function trinity_ph_get_audio_posthash($post_id) {
    $post_hashes = trinity_ph_get_posthashes_for_post_id($post_id);
    if (!$post_hashes) return;

    return $post_hashes[TRINITY_AUDIO_POST_META_MAP[TRINITY_AUDIO_TITLE_CONTENT]];
  }

  function trinity_ph_cleanup() {
    trinity_phbu_set_batch_retry(0);
  }