0) ob_end_clean(); } if (!function_exists('wp_insert_post') || !function_exists('get_option')) { iw_plain('WordPress yüklenemedi', 500); } } function iw_e($value) { return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function iw_cut($value, $max) { return function_exists('mb_substr') ? mb_substr($value, 0, $max, 'UTF-8') : substr($value, 0, $max); } function iw_text($value, $max) { $value = trim(preg_replace('/\s+/u', ' ', strip_tags((string)$value)) ?? ''); return iw_cut($value, $max); } function iw_slug($value) { if (function_exists('sanitize_title')) { $slug = (string)sanitize_title($value); return substr($slug !== '' ? $slug : 'article', 0, 80); } $value = strtolower(trim($value)); $value = trim((string)preg_replace('/[^a-z0-9]+/', '-', $value), '-'); return substr($value !== '' ? $value : 'article', 0, 80); } function iw_valid_http_url($url) { if (!filter_var($url, FILTER_VALIDATE_URL)) return false; return in_array(strtolower((string)parse_url($url, PHP_URL_SCHEME)), ['http', 'https'], true); } function iw_config() { $value = get_option(IW_OPTION_CONFIG, []); return is_array($value) ? $value : []; } function iw_save_config($config) { update_option(IW_OPTION_CONFIG, $config, false); } function iw_setup_code() { $existing = strtoupper(trim((string)get_option(IW_OPTION_SETUP, ''))); if (preg_match('/^[A-Z0-9]{8}$/', $existing)) return $existing; $alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; $code = ''; for ($i = 0; $i < 8; $i++) { $code .= $alphabet[random_int(0, strlen($alphabet) - 1)]; } update_option(IW_OPTION_SETUP, $code, false); return $code; } function iw_set_state($state) { $allowed = ['Sipariş alındı', 'Sipariş tamamlanıyor', 'Sipariş tamamlandı']; if (!in_array($state, $allowed, true)) return; update_option(IW_OPTION_STATE, ['state'=>$state, 'updated_at'=>gmdate('c')], false); } function iw_get_state() { $row = get_option(IW_OPTION_STATE, []); $state = is_array($row) ? (string)($row['state'] ?? '') : ''; return in_array($state, ['Sipariş alındı', 'Sipariş tamamlanıyor', 'Sipariş tamamlandı'], true) ? $state : 'Sipariş alındı'; } function iw_log($event, $context = []) { error_log('[IndexWell Publisher] ' . json_encode([ 'time'=>gmdate('c'), 'event'=>$event, 'context'=>$context, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); } function iw_verify_nonce($nonce, $timestamp) { if (!preg_match('/^[A-Za-z0-9_-]{16,128}$/', $nonce)) { iw_json(['ok'=>false, 'error'=>'Invalid nonce.'], 401); } $key = 'iw_pub_nonce_' . substr(hash('sha256', $nonce), 0, 40); if (get_transient($key) !== false) { iw_json(['ok'=>false, 'error'=>'Replay request rejected.'], 409); } set_transient($key, $timestamp, 15 * MINUTE_IN_SECONDS); } function iw_verify_signed_request($body, $config) { $secret = (string)($config['secret'] ?? ''); if (strlen($secret) < 32) iw_json(['ok'=>false, 'error'=>'Publisher is not paired.'], 503); $timestamp = (int)($_SERVER['HTTP_X_INDEXWELL_TIMESTAMP'] ?? 0); $nonce = trim((string)($_SERVER['HTTP_X_INDEXWELL_NONCE'] ?? '')); $signature = strtolower(trim((string)($_SERVER['HTTP_X_INDEXWELL_SIGNATURE'] ?? ''))); if ($timestamp < 1 || abs(time() - $timestamp) > IW_MAX_CLOCK_SKEW) { iw_json(['ok'=>false, 'error'=>'Expired request timestamp.'], 401); } if (!preg_match('/^[a-f0-9]{64}$/', $signature)) { iw_json(['ok'=>false, 'error'=>'Invalid signature.'], 401); } $expected = hash_hmac('sha256', $timestamp . "\n" . $nonce . "\n" . $body, $secret); if (!hash_equals($expected, $signature)) { iw_log('signature_rejected'); iw_json(['ok'=>false, 'error'=>'Signature verification failed.'], 401); } iw_verify_nonce($nonce, $timestamp); } function iw_wp_author_id() { if (function_exists('get_users')) { $users = get_users([ 'role'=>'administrator', 'number'=>1, 'fields'=>'ID', 'orderby'=>'ID', 'order'=>'ASC', ]); if (is_array($users) && isset($users[0])) return max(1, (int)$users[0]); } return 1; } function iw_anchor_html($anchor, $target, $linkRel) { $rel = $linkRel === 'nofollow' ? ' rel="nofollow noopener noreferrer"' : ' rel="noopener noreferrer"'; return '' . iw_e($anchor) . ''; } function iw_paragraphs($text) { $parts = preg_split('/\n\s*\n|\r\n\s*\r\n/', trim($text)) ?: []; $out = []; foreach ($parts as $part) { $part = trim($part); if ($part !== '') $out[] = '
' . nl2br(iw_e($part), false) . '
'; } return $out; } function iw_article_content($payload, $orderId) { $title = iw_text($payload['title'] ?? '', 180); $intro = trim((string)($payload['intro'] ?? '')); $anchor = iw_text($payload['anchor_text'] ?? '', 180); $target = trim((string)($payload['target_url'] ?? '')); $linkRel = strtolower(trim((string)($payload['link_rel'] ?? 'dofollow'))); if ($title === '' || $anchor === '' || !iw_valid_http_url($target)) { throw new RuntimeException('Article title, anchor or target URL is invalid.'); } if (!in_array($linkRel, ['dofollow', 'nofollow'], true)) $linkRel = 'dofollow'; $anchorLink = iw_anchor_html($anchor, $target, $linkRel); $sentences = [ 'Konu hakkında güncel ayrıntılar için %s kaynağı incelenebilir.', 'İlgili bilgi ve güncel erişim ayrıntıları %s bağlantısında yer alır.', 'Daha ayrıntılı değerlendirme için %s sayfası referans olarak kullanılabilir.', 'Güncel bilgiye ulaşmak isteyen kullanıcılar %s kaynağını kontrol edebilir.', 'Konuya ilişkin ek bilgiler %s bağlantısı üzerinden doğrulanabilir.', 'Güncel açıklamalar ve erişim bilgileri için %s sayfasına bakılabilir.', ]; $sentence = sprintf($sentences[hexdec(substr(hash('sha256', $orderId), 0, 2)) % count($sentences)], $anchorLink); $parts = iw_paragraphs($intro); if ($parts === []) { $parts[] = '' . $sentence . '
'; } else { $insertAt = count($parts) > 1 ? 1 : count($parts); array_splice($parts, $insertAt, 0, ['' . $sentence . '
']); } $sections = ''; foreach ((array)($payload['sections'] ?? []) as $section) { if (!is_array($section)) continue; $heading = iw_text($section['heading'] ?? '', 180); $body = trim((string)($section['body'] ?? '')); if ($heading !== '') $sections .= '