更新
This commit is contained in:
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace app\common\service\qywx;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/** 企业微信获客助手链接校验。 */
|
||||
class QywxCustomerAcquisitionLinkService
|
||||
{
|
||||
@@ -39,4 +41,98 @@ class QywxCustomerAcquisitionLinkService
|
||||
{
|
||||
return 'https://work.weixin.qq.com/ca/xxxxxxxx';
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化企业微信 create_link/get 返回的链接详情。
|
||||
*
|
||||
* get 接口把 range、priority_option 放在响应根级,link 只包含链接本身;
|
||||
* 旧响应或测试桩可能把这些字段放在 link 内,因此保留兼容回退。
|
||||
*
|
||||
* @return array{
|
||||
* link_id:string,
|
||||
* link_name:string,
|
||||
* url:string,
|
||||
* create_time:int,
|
||||
* range_userids:list<string>,
|
||||
* range_department_ids:list<string>,
|
||||
* skip_verify:bool,
|
||||
* priority_option:array<string,mixed>,
|
||||
* snapshot:array<string,mixed>
|
||||
* }
|
||||
*/
|
||||
public static function normaliseRemoteResponse(array $response, string $fallbackId = ''): array
|
||||
{
|
||||
$link = isset($response['link']) && is_array($response['link']) ? $response['link'] : $response;
|
||||
$range = isset($response['range']) && is_array($response['range'])
|
||||
? $response['range']
|
||||
: (isset($link['range']) && is_array($link['range']) ? $link['range'] : []);
|
||||
$priorityOption = isset($response['priority_option']) && is_array($response['priority_option'])
|
||||
? $response['priority_option']
|
||||
: (isset($link['priority_option']) && is_array($link['priority_option']) ? $link['priority_option'] : []);
|
||||
$linkId = trim((string) ($link['link_id'] ?? $response['link_id'] ?? $fallbackId));
|
||||
$url = trim((string) ($link['url'] ?? $link['link_url'] ?? $response['url'] ?? ''));
|
||||
if ($linkId === '') {
|
||||
throw new RuntimeException('企业微信获客链接详情缺少 link_id');
|
||||
}
|
||||
if (!self::isAllowed($url)) {
|
||||
throw new RuntimeException('企业微信获客链接详情未返回有效的 https://work.weixin.qq.com/ca/... 地址');
|
||||
}
|
||||
|
||||
return [
|
||||
'link_id' => $linkId,
|
||||
'link_name' => trim((string) ($link['link_name'] ?? $link['name'] ?? $linkId)),
|
||||
'url' => $url,
|
||||
'create_time' => max(0, (int) ($link['create_time'] ?? 0)),
|
||||
'range_userids' => self::normaliseScalarList($range['user_list'] ?? []),
|
||||
'range_department_ids' => self::normaliseScalarList($range['department_list'] ?? []),
|
||||
'skip_verify' => !empty($link['skip_verify']),
|
||||
'priority_option' => $priorityOption,
|
||||
'snapshot' => $response,
|
||||
];
|
||||
}
|
||||
|
||||
/** 追加或替换企业微信获客助手的自定义渠道标识。 */
|
||||
public static function withCustomerChannel(string $url, string $channel): string
|
||||
{
|
||||
$url = trim($url);
|
||||
$channel = trim($channel);
|
||||
if (!self::isAllowed($url) || $channel === '' || strlen($channel) > 64) {
|
||||
return '';
|
||||
}
|
||||
// 冒号在查询参数中是合法字符,保留“命名空间:编号”的可读结构;其余字符仍编码。
|
||||
$parameter = 'customer_channel=' . str_replace('%3A', ':', rawurlencode($channel));
|
||||
if (preg_match('/([?&])customer_channel=[^&#]*/i', $url) === 1) {
|
||||
return (string) preg_replace_callback(
|
||||
'/([?&])customer_channel=[^&#]*/i',
|
||||
static fn (array $matches): string => $matches[1] . $parameter,
|
||||
$url,
|
||||
1
|
||||
);
|
||||
}
|
||||
$fragment = '';
|
||||
$fragmentPosition = strpos($url, '#');
|
||||
if ($fragmentPosition !== false) {
|
||||
$fragment = substr($url, $fragmentPosition);
|
||||
$url = substr($url, 0, $fragmentPosition);
|
||||
}
|
||||
|
||||
return $url . (str_contains($url, '?') ? '&' : '?') . $parameter . $fragment;
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
private static function normaliseScalarList(mixed $values): array
|
||||
{
|
||||
$result = [];
|
||||
$seen = [];
|
||||
foreach ((array) $values as $value) {
|
||||
$normalised = trim((string) $value);
|
||||
$key = 'value:' . $normalised;
|
||||
if ($normalised !== '' && !isset($seen[$key])) {
|
||||
$seen[$key] = true;
|
||||
$result[] = $normalised;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user