Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / infrastructure / javelin / markup.php
blob1a0c98d983c8385be2d8a1be82dfc40af0b9a221
1 <?php
3 function javelin_tag(
4 $tag,
5 array $attributes = array(),
6 $content = null) {
8 if (isset($attributes['sigil']) ||
9 isset($attributes['meta']) ||
10 isset($attributes['mustcapture'])) {
11 foreach ($attributes as $k => $v) {
12 switch ($k) {
13 case 'sigil':
14 if ($v !== null) {
15 $attributes['data-sigil'] = $v;
17 unset($attributes[$k]);
18 break;
19 case 'meta':
20 if ($v !== null) {
21 $response = CelerityAPI::getStaticResourceResponse();
22 $id = $response->addMetadata($v);
23 $attributes['data-meta'] = $id;
25 unset($attributes[$k]);
26 break;
27 case 'mustcapture':
28 if ($v) {
29 $attributes['data-mustcapture'] = '1';
30 } else {
31 unset($attributes['data-mustcapture']);
33 unset($attributes[$k]);
34 break;
39 if (isset($attributes['aural'])) {
40 if ($attributes['aural']) {
41 $class = idx($attributes, 'class', '');
42 $class = rtrim('aural-only '.$class);
43 $attributes['class'] = $class;
44 } else {
45 $class = idx($attributes, 'class', '');
46 $class = rtrim('visual-only '.$class);
47 $attributes['class'] = $class;
48 $attributes['aria-hidden'] = 'true';
50 unset($attributes['aural']);
53 if (isset($attributes['print'])) {
54 if ($attributes['print']) {
55 $class = idx($attributes, 'class', '');
56 $class = rtrim('print-only '.$class);
57 $attributes['class'] = $class;
59 // NOTE: Alternative print content is hidden from screen readers.
60 $attributes['aria-hidden'] = 'true';
61 } else {
62 $class = idx($attributes, 'class', '');
63 $class = rtrim('screen-only '.$class);
64 $attributes['class'] = $class;
66 unset($attributes['print']);
70 return phutil_tag($tag, $attributes, $content);
73 function phabricator_form(PhabricatorUser $user, $attributes, $content) {
74 $body = array();
76 $http_method = idx($attributes, 'method');
77 $is_post = (strcasecmp($http_method, 'POST') === 0);
79 $http_action = idx($attributes, 'action');
80 $is_absolute_uri = false;
81 if ($http_action != null) {
82 $is_absolute_uri = preg_match('#^(https?:|//)#', $http_action);
85 if ($is_post) {
87 // NOTE: We only include CSRF tokens if a URI is a local URI on the same
88 // domain. This is an important security feature and prevents forms which
89 // submit to foreign sites from leaking CSRF tokens.
91 // In some cases, we may construct a fully-qualified local URI. For example,
92 // we can construct these for download links, depending on configuration.
94 // These forms do not receive CSRF tokens, even though they safely could.
95 // This can be confusing, if you're developing for Phabricator and
96 // manage to construct a local form with a fully-qualified URI, since it
97 // won't get CSRF tokens and you'll get an exception at the other end of
98 // the request which is a bit disconnected from the actual root cause.
100 // However, this is rare, and there are reasonable cases where this
101 // construction occurs legitimately, and the simplest fix is to omit CSRF
102 // tokens for these URIs in all cases. The error message you receive also
103 // gives you some hints as to this potential source of error.
105 if (!$is_absolute_uri) {
106 $body[] = phutil_tag(
107 'input',
108 array(
109 'type' => 'hidden',
110 'name' => AphrontRequest::getCSRFTokenName(),
111 'value' => $user->getCSRFToken(),
114 $body[] = phutil_tag(
115 'input',
116 array(
117 'type' => 'hidden',
118 'name' => '__form__',
119 'value' => true,
122 // If the profiler was active for this request, keep it active for any
123 // forms submitted from this page.
124 if (DarkConsoleXHProfPluginAPI::isProfilerRequested()) {
125 $body[] = phutil_tag(
126 'input',
127 array(
128 'type' => 'hidden',
129 'name' => '__profile__',
130 'value' => true,
137 if (is_array($content)) {
138 $body = array_merge($body, $content);
139 } else {
140 $body[] = $content;
143 return javelin_tag('form', $attributes, $body);