Merge pull request #22335 from braders/participant-static-method
[civicrm-core.git] / CRM / Mailing / BAO / TrackableURL.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17 class CRM_Mailing_BAO_TrackableURL extends CRM_Mailing_DAO_TrackableURL {
18
19 /**
20 * Class constructor.
21 */
22 public function __construct() {
23 parent::__construct();
24 }
25
26 /**
27 * Given a url, mailing id and queue event id, find or construct a
28 * trackable url and redirect url.
29 *
30 * @param string $url
31 * The target url to track.
32 * @param int $mailing_id
33 * The id of the mailing.
34 * @param int $queue_id
35 * The queue event id (contact clicking through).
36 *
37 * @return string
38 * The redirect/tracking url
39 */
40 public static function getTrackerURL($url, $mailing_id, $queue_id) {
41 if (strpos($url, '{') !== FALSE) {
42 return self::getTrackerURLForUrlWithTokens($url, $mailing_id, $queue_id);
43 }
44 else {
45 return self::getBasicTrackerURL($url, $mailing_id, $queue_id);
46 }
47 }
48
49 private static function getBasicTrackerURL($url, $mailing_id, $queue_id) {
50 static $urlCache = [];
51
52 if (array_key_exists($mailing_id . $url, $urlCache)) {
53 return $urlCache[$mailing_id . $url] . "&qid=$queue_id";
54 }
55
56 // hack for basic CRM-1014 and CRM-1151 and CRM-3492 compliance:
57 // let's not replace possible image URLs, CiviMail URLs or internal anchor URLs
58 if (preg_match('/\.(png|jpg|jpeg|gif|css)[\'"]?$/i', $url)
59 or substr_count($url, 'civicrm/extern/')
60 or substr_count($url, 'civicrm/mailing/')
61 or ($url[0] === '#')
62 ) {
63 // let's not cache these, so they don't get &qid= appended to them
64 return $url;
65 }
66 else {
67
68 $hrefExists = FALSE;
69
70 $tracker = new CRM_Mailing_BAO_TrackableURL();
71 if (preg_match('/^href/i', $url)) {
72 $url = preg_replace('/^href[ ]*=[ ]*[\'"](.*?)[\'"]$/i', '$1', $url);
73 $hrefExists = TRUE;
74 }
75
76 $tracker->url = $url;
77 $tracker->mailing_id = $mailing_id;
78
79 if (!$tracker->find(TRUE)) {
80 $tracker->save();
81 }
82 $id = $tracker->id;
83
84 $redirect = CRM_Utils_System::externUrl('extern/url', "u=$id");
85 $urlCache[$mailing_id . $url] = $redirect;
86 }
87
88 // This looks silly - calling the hook twice. This smells like an accident. Restoring old cache-based lookup.
89 // $returnUrl = CRM_Utils_System::externUrl('extern/url', "u=$id&qid=$queue_id");
90 $returnUrl = "{$urlCache[$mailing_id . $url]}&qid={$queue_id}";
91
92 if ($hrefExists) {
93 $returnUrl = "href='{$returnUrl}' rel='nofollow'";
94 }
95
96 return $returnUrl;
97 }
98
99 /**
100 * Create a trackable URL for a URL with tokens.
101 *
102 * @param string $url
103 * @param int $mailing_id
104 * @param int|string $queue_id
105 *
106 * @return string
107 */
108 private static function getTrackerURLForUrlWithTokens($url, $mailing_id, $queue_id) {
109
110 // Parse the URL.
111 // (not using parse_url because it's messy to reassemble)
112 if (!preg_match('/^([^?#]+)([?][^#]*)?(#.*)?$/', $url, $parsed)) {
113 // Failed to parse it, give up and don't track it.
114 return $url;
115 }
116
117 // If we have a token in the URL + path section, we can't tokenise.
118 if (strpos($parsed[1], '{') !== FALSE) {
119 return $url;
120 }
121
122 $trackable_url = $parsed[1];
123
124 // Process the query parameters, if there are any.
125 $tokenised_params = [];
126 $static_params = [];
127 if (!empty($parsed[2])) {
128 $query_key_value_pairs = explode('&', substr($parsed[2], 1));
129
130 // Separate the tokenised from the static parts.
131 foreach ($query_key_value_pairs as $_) {
132 if (strpos($_, '{') === FALSE) {
133 $static_params[] = $_;
134 }
135 else {
136 $tokenised_params[] = $_;
137 }
138 }
139 // Add the static params to the trackable part.
140 if ($static_params) {
141 $trackable_url .= '?' . implode('&', $static_params);
142 }
143 }
144
145 // Get trackable URL.
146 $data = self::getBasicTrackerURL($trackable_url, $mailing_id, $queue_id);
147
148 // Append the tokenised bits and the fragment.
149 if ($tokenised_params) {
150 // We know the URL will already have the '?'
151 $data .= '&' . implode('&', $tokenised_params);
152 }
153 if (!empty($parsed[3])) {
154 $data .= $parsed[3];
155 }
156 return $data;
157 }
158
159 /**
160 * @param $url
161 * @param $mailing_id
162 *
163 * @return int
164 * Url id of the given url and mail
165 */
166 public static function getTrackerURLId($url, $mailing_id) {
167 $tracker = new CRM_Mailing_BAO_TrackableURL();
168 $tracker->url = $url;
169 $tracker->mailing_id = $mailing_id;
170 if ($tracker->find(TRUE)) {
171 return $tracker->id;
172 }
173
174 return NULL;
175 }
176
177 }