mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
411 Commits
3.0.0-beta
...
2.7.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf433f2f80 | ||
|
|
ae94e58a43 | ||
|
|
cda017fa4f | ||
|
|
dad22f6f83 | ||
|
|
9077f7ba37 | ||
|
|
957ff40f30 | ||
|
|
aff9c7748b | ||
|
|
e518d34bc9 | ||
|
|
f0141530b9 | ||
|
|
ce5096a896 | ||
|
|
23e0ed5e56 | ||
|
|
d412a52fcc | ||
|
|
3e18ad590f | ||
|
|
22111bf667 | ||
|
|
6d0c46595d | ||
|
|
d292a6b0c3 | ||
|
|
74702c8d06 | ||
|
|
e9c91d986d | ||
|
|
70a6b276ca | ||
|
|
f77361ceb2 | ||
|
|
75f4751b82 | ||
|
|
b56f2f56f1 | ||
|
|
68d44fa981 | ||
|
|
7e5307bd96 | ||
|
|
cd010afb48 | ||
|
|
0cf8d731bb | ||
|
|
189ca3c555 | ||
|
|
1e1f1f78bf | ||
|
|
1494604740 | ||
|
|
583ab98210 | ||
|
|
88d743b1cc | ||
|
|
7ac4bc95bb | ||
|
|
d431811725 | ||
|
|
7512f721e9 | ||
|
|
bdfe3a3b35 | ||
|
|
5cf391c3bb | ||
|
|
4c1df9927d | ||
|
|
74003f12c1 | ||
|
|
3bc12b0434 | ||
|
|
02a0969b53 | ||
|
|
d78a25ee4e | ||
|
|
7a6a3d1ac0 | ||
|
|
6b32be0899 | ||
|
|
33c2168af2 | ||
|
|
ae021064a4 | ||
|
|
0a61169326 | ||
|
|
d7e5705520 | ||
|
|
35a8b501c9 | ||
|
|
8fa616f440 | ||
|
|
5829e698da | ||
|
|
df347b90e5 | ||
|
|
bb861aa262 | ||
|
|
f9ac07830e | ||
|
|
0f4c7ac90f | ||
|
|
0687f9a0a9 | ||
|
|
6e75ab2889 | ||
|
|
b90d29d448 | ||
|
|
1f78bf4119 | ||
|
|
5d25e77189 | ||
|
|
d9dabf25da | ||
|
|
73af605892 | ||
|
|
f70f95c119 | ||
|
|
53c50cf6fc | ||
|
|
f19d1472c5 | ||
|
|
eef00502cd | ||
|
|
0b1caac195 | ||
|
|
e900a44d47 | ||
|
|
a3de9fa898 | ||
|
|
8b0154cc62 | ||
|
|
1a225bf55b | ||
|
|
24d19cd8d6 | ||
|
|
c25a4a7346 | ||
|
|
20fb7b241f | ||
|
|
a0553e1195 | ||
|
|
f40141072a | ||
|
|
c759856a61 | ||
|
|
237b181eec | ||
|
|
48957fd2f0 | ||
|
|
8a99c37200 | ||
|
|
d388c3fd3d | ||
|
|
1b8e48539d | ||
|
|
104beff158 | ||
|
|
4712569a36 | ||
|
|
2392f4a902 | ||
|
|
a0f28a9098 | ||
|
|
6df622e8ed | ||
|
|
54eb9d081b | ||
|
|
9f60f27636 | ||
|
|
ba59643f52 | ||
|
|
01c02a75a8 | ||
|
|
f5b3e5f341 | ||
|
|
9b825cb529 | ||
|
|
3f326f0913 | ||
|
|
ec86bd246a | ||
|
|
aa90d5b6ab | ||
|
|
53d2129bd1 | ||
|
|
00e8c11ec2 | ||
|
|
617b6b991f | ||
|
|
b3ea1050eb | ||
|
|
ca98066d68 | ||
|
|
352f7c8675 | ||
|
|
df5d514c28 | ||
|
|
16663797b2 | ||
|
|
4099376472 | ||
|
|
6d3118d9e9 | ||
|
|
4c585614cd | ||
|
|
9674378c56 | ||
|
|
9e314ba77b | ||
|
|
cdd7dcdc5c | ||
|
|
34bed5ec4f | ||
|
|
3ea82e37d5 | ||
|
|
596c62aec8 | ||
|
|
265415030e | ||
|
|
3d26f28f9b | ||
|
|
0abec767e3 | ||
|
|
9fd10bd73e | ||
|
|
95dafc87c0 | ||
|
|
fe1790793e | ||
|
|
ddb95dc64e | ||
|
|
f6f9ee26e1 | ||
|
|
21faa92904 | ||
|
|
622f40c06c | ||
|
|
964134cb60 | ||
|
|
72f498a63b | ||
|
|
f9a1f68295 | ||
|
|
9b67b0b9d5 | ||
|
|
f798ef1d76 | ||
|
|
754946bf62 | ||
|
|
a6580e3cd8 | ||
|
|
da6621f2ff | ||
|
|
f2d42a7e56 | ||
|
|
d01e4b4a85 | ||
|
|
f57d1f1de3 | ||
|
|
a3f122184c | ||
|
|
16fcddc249 | ||
|
|
2a9c9be36a | ||
|
|
ca3aae23a1 | ||
|
|
4dd384e418 | ||
|
|
80e7313b24 | ||
|
|
183c3c1baf | ||
|
|
160c52fe81 | ||
|
|
5f0a820b4a | ||
|
|
03ef4246bf | ||
|
|
534e7cf59d | ||
|
|
e1645f6903 | ||
|
|
61a2d200b4 | ||
|
|
3d6bbe4029 | ||
|
|
44eda676a3 | ||
|
|
eac6f07823 | ||
|
|
424e2a5745 | ||
|
|
0ef4fee0b4 | ||
|
|
1d45eff9b0 | ||
|
|
8e97279401 | ||
|
|
932ef780fd | ||
|
|
59424c3126 | ||
|
|
562dd8fc21 | ||
|
|
cf745554fb | ||
|
|
e909eac98e | ||
|
|
5e42efc3ec | ||
|
|
eb1d56f439 | ||
|
|
644e1ac4f6 | ||
|
|
4c88dbd9ac | ||
|
|
11d2e62e67 | ||
|
|
58b27a9daa | ||
|
|
caf939bf58 | ||
|
|
8c217fdac9 | ||
|
|
6b80bbeaa2 | ||
|
|
134736dce5 | ||
|
|
4b870bcf1e | ||
|
|
dd8a4a0082 | ||
|
|
c2607c4223 | ||
|
|
1fb0911710 | ||
|
|
b348e0ff27 | ||
|
|
4646a05c7a | ||
|
|
c5527c106c | ||
|
|
5eac1b8730 | ||
|
|
0de15d040f | ||
|
|
c4ae94fd4c | ||
|
|
1e8818984e | ||
|
|
a023f73509 | ||
|
|
6f0e1a7f47 | ||
|
|
0ef9bb1a47 | ||
|
|
71ceedc4bb | ||
|
|
73c3c1249f | ||
|
|
88a10dba28 | ||
|
|
001e222f67 | ||
|
|
af8bcdc242 | ||
|
|
f4c7afc148 | ||
|
|
b19c73a36e | ||
|
|
5fe0d0b94f | ||
|
|
f8d435d5f3 | ||
|
|
f15ef36fd1 | ||
|
|
64b25c4daa | ||
|
|
d0ba0d193b | ||
|
|
8e6e2432d3 | ||
|
|
83ec19dfca | ||
|
|
6e619f2c35 | ||
|
|
163ba41e8d | ||
|
|
ec143c43db | ||
|
|
cacf0004a5 | ||
|
|
cb39541e2a | ||
|
|
b9ddadeb44 | ||
|
|
11e811cc4b | ||
|
|
e422adb0d0 | ||
|
|
e02d9f3f0e | ||
|
|
e831d66b76 | ||
|
|
6fa2d47780 | ||
|
|
e691454339 | ||
|
|
92997e3e57 | ||
|
|
631b38a160 | ||
|
|
7ce5712b71 | ||
|
|
61137a6f65 | ||
|
|
0080a2e733 | ||
|
|
7f4fddb378 | ||
|
|
a71cb97db3 | ||
|
|
4c99f497cc | ||
|
|
0205cdf713 | ||
|
|
39fc59a8b2 | ||
|
|
107c9adf60 | ||
|
|
d29880b1b8 | ||
|
|
2d156bd77b | ||
|
|
d122dbfdd6 | ||
|
|
46d58e6512 | ||
|
|
93a138606f | ||
|
|
70074ee1cb | ||
|
|
d28ccb264f | ||
|
|
8ab38854a8 | ||
|
|
9f27cf2b84 | ||
|
|
f78986009f | ||
|
|
809ea2eb49 | ||
|
|
968a0e5f3a | ||
|
|
83e98ef2b8 | ||
|
|
5048421bfa | ||
|
|
788caf9c50 | ||
|
|
35165568af | ||
|
|
4a67819f87 | ||
|
|
81c39c35cd | ||
|
|
4caf52f1ae | ||
|
|
0c5b845c8a | ||
|
|
cdfdb1f2ca | ||
|
|
f29a8792af | ||
|
|
b494ff2ce6 | ||
|
|
df1e19dc43 | ||
|
|
9ad341f73a | ||
|
|
03e9bcd47a | ||
|
|
55effea0a3 | ||
|
|
dfaa973359 | ||
|
|
2e45b20fc4 | ||
|
|
e89090f0ec | ||
|
|
47db04bcb7 | ||
|
|
a49c451ae4 | ||
|
|
25c3704990 | ||
|
|
3000659e86 | ||
|
|
ce36c00b83 | ||
|
|
2a3e6384d9 | ||
|
|
dd7e73e413 | ||
|
|
1709082e39 | ||
|
|
41f6e85673 | ||
|
|
3ef3166bd5 | ||
|
|
299ad7e753 | ||
|
|
84280a3b5f | ||
|
|
b4fc647845 | ||
|
|
17612f88d3 | ||
|
|
e14845728c | ||
|
|
4e80fc0f76 | ||
|
|
fcfcf85e0d | ||
|
|
f0715baf7d | ||
|
|
45b5c39af7 | ||
|
|
dbc3da7bc3 | ||
|
|
ebc9fa684a | ||
|
|
606bdc1909 | ||
|
|
7495fb9af4 | ||
|
|
75dbad7406 | ||
|
|
3381c085f4 | ||
|
|
9b6f7d94f4 | ||
|
|
64e8aa5fee | ||
|
|
477128ad53 | ||
|
|
aa66bec783 | ||
|
|
1da52a8517 | ||
|
|
cbd2181862 | ||
|
|
4180a41f27 | ||
|
|
a43adcd202 | ||
|
|
e8e170fb06 | ||
|
|
5ac5d649aa | ||
|
|
decb802df4 | ||
|
|
cacc3a3085 | ||
|
|
0fd2ea6a47 | ||
|
|
426f275c03 | ||
|
|
693a861e7d | ||
|
|
0ee6c60e94 | ||
|
|
a663e9fded | ||
|
|
b3bf516b20 | ||
|
|
c2408b74cd | ||
|
|
6855c2f83a | ||
|
|
b11bf30881 | ||
|
|
64736f1463 | ||
|
|
930b224ca2 | ||
|
|
92b61c7491 | ||
|
|
e530cbb4f2 | ||
|
|
ddb8378fe6 | ||
|
|
47db23d91c | ||
|
|
fc1f701bf6 | ||
|
|
365c7bb89e | ||
|
|
b073e4385c | ||
|
|
f9359431fe | ||
|
|
25e560fdaa | ||
|
|
6bf25f90bc | ||
|
|
3db20e8028 | ||
|
|
b190d0e385 | ||
|
|
93f273a287 | ||
|
|
04e7616c84 | ||
|
|
219b970703 | ||
|
|
76c139253e | ||
|
|
02b09c2535 | ||
|
|
10cfb373f2 | ||
|
|
69578d5d07 | ||
|
|
97d6d413bb | ||
|
|
7e0d5d64ce | ||
|
|
3f8f57fa9a | ||
|
|
eb2a615bd2 | ||
|
|
0432727ace | ||
|
|
e6d61d1ebd | ||
|
|
f916f9cde8 | ||
|
|
5e61388b65 | ||
|
|
910bbe1160 | ||
|
|
9addc4a7ca | ||
|
|
5ed71ecb96 | ||
|
|
dab0e372d0 | ||
|
|
dfd1d5fe35 | ||
|
|
d289457c0c | ||
|
|
f52b3bff0d | ||
|
|
b6b17733bf | ||
|
|
c1c2d027c3 | ||
|
|
5269096ecd | ||
|
|
e4c68936a0 | ||
|
|
4db5d4c08d | ||
|
|
3511867ba3 | ||
|
|
7934f9b9dc | ||
|
|
7f2eef4a24 | ||
|
|
8a65a592f3 | ||
|
|
7d6b019cfa | ||
|
|
5e48400cb1 | ||
|
|
252562ace9 | ||
|
|
c9c32b0de1 | ||
|
|
770ac8ffe5 | ||
|
|
dcfdb2d0a9 | ||
|
|
0cbf34ba5a | ||
|
|
f1037147a9 | ||
|
|
bea52d5fb9 | ||
|
|
b6fac4b411 | ||
|
|
d8a77c22a3 | ||
|
|
ed3c387712 | ||
|
|
312a5b246b | ||
|
|
903de43589 | ||
|
|
2d67594ccf | ||
|
|
65f9f86bcc | ||
|
|
efaf53e568 | ||
|
|
81a2a9278c | ||
|
|
e15d4bfab6 | ||
|
|
77880c3675 | ||
|
|
3559425fc1 | ||
|
|
d8c4251c03 | ||
|
|
9437e689fd | ||
|
|
a79459bc53 | ||
|
|
500bd15843 | ||
|
|
3e8dd2f4a5 | ||
|
|
d0fade9ce1 | ||
|
|
51a49dfce8 | ||
|
|
066b71686d | ||
|
|
be633001a5 | ||
|
|
84426c6634 | ||
|
|
dbaf924171 | ||
|
|
8adf743cc7 | ||
|
|
75450ded1d | ||
|
|
bcca6ac720 | ||
|
|
865f9f4f67 | ||
|
|
a7e54d4bad | ||
|
|
2beb795f9a | ||
|
|
6847d8a5c7 | ||
|
|
06985d3cf2 | ||
|
|
8c7f7abaab | ||
|
|
e8d314e1f6 | ||
|
|
e29f1825be | ||
|
|
908a48e0a1 | ||
|
|
9b854dbcc7 | ||
|
|
7757f1f2d2 | ||
|
|
a353317746 | ||
|
|
723eb90160 | ||
|
|
8ea5be4ead | ||
|
|
b3f827ed5e | ||
|
|
eaf8a187aa | ||
|
|
34f64c61f6 | ||
|
|
8154e718a1 | ||
|
|
b5369a0c03 | ||
|
|
2bc61caab1 | ||
|
|
8f0a5fcaf9 | ||
|
|
fe3512cb5f | ||
|
|
fdc987f367 | ||
|
|
ec1dcc8df6 | ||
|
|
47ed863da9 | ||
|
|
88290f9e91 | ||
|
|
cfdbc8ae62 | ||
|
|
aaa8f6d311 | ||
|
|
1c983e8093 | ||
|
|
92a9a8c65f | ||
|
|
27217815d1 | ||
|
|
2fe4265223 | ||
|
|
2b71ea108a | ||
|
|
ed719e13c7 | ||
|
|
2d705c6697 | ||
|
|
c98ad106c4 |
48
.gitattributes
vendored
Normal file
48
.gitattributes
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.bash text eol=lf
|
||||
*.bat text eol=lf
|
||||
*.cmd text eol=lf
|
||||
*.css text eol=lf
|
||||
*.scss text eol=lf
|
||||
*.dist text eol=lf
|
||||
.editorconfig text eol=lf
|
||||
.env* text eol=lf
|
||||
.gitignore text eol=lf
|
||||
.htaccess text eol=lf
|
||||
*.htm text eol=lf
|
||||
*.html text eol=lf
|
||||
*.ini text eol=lf
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.lock text eol=lf
|
||||
*.md text eol=lf
|
||||
*.php text eol=lf
|
||||
*.php_cs text eol=lf
|
||||
*.php8 text eol=lf
|
||||
*.plex text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.svg text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.twig text eol=lf
|
||||
*.txt text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.xsd text eol=lf
|
||||
*.yaml text eol=lf
|
||||
*.yml text eol=lf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpeg binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.pdf binary
|
||||
*.swf binary
|
||||
*.zip binary
|
||||
*.ttf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -6,12 +6,6 @@
|
||||
# maintenance mode (N°2240)
|
||||
/.maintenance
|
||||
|
||||
# listing prevention in conf directory
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
@@ -19,6 +13,7 @@ test/vendor/*
|
||||
# all conf but listing prevention
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# all datas but listing prevention
|
||||
@@ -37,9 +32,13 @@ test/vendor/*
|
||||
!/log/index.php
|
||||
!/log/web.config
|
||||
|
||||
# PHPUnit cache file
|
||||
/test/.phpunit.result.cache
|
||||
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
!/.idea/IntelliLang.xml
|
||||
|
||||
# doc. generation
|
||||
/.doc/vendor
|
||||
|
||||
15
.idea/IntelliLang.xml
generated
Normal file
15
.idea/IntelliLang.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="LanguageInjectionConfiguration">
|
||||
<injection language="InjectablePHP" injector-id="xml">
|
||||
<display-name>iTop - Class method code</display-name>
|
||||
<place><![CDATA[xmlTag().withLocalName(string().equalTo("code"))]]></place>
|
||||
<xpath-condition>name(..) = 'method' and count(/itop_design) = 1</xpath-condition>
|
||||
</injection>
|
||||
<injection language="InjectablePHP" injector-id="xml">
|
||||
<display-name>iTop - Snippet code</display-name>
|
||||
<place><![CDATA[xmlTag().withLocalName(string().equalTo("snippet"))]]></place>
|
||||
<xpath-condition>name(..) = 'snippets' and count(/itop_design) = 1</xpath-condition>
|
||||
</injection>
|
||||
</component>
|
||||
</project>
|
||||
@@ -36,22 +36,38 @@ clearstatcache();
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
echo "\n";
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (! preg_match('#[tT]ests?/?$#', $sDir))
|
||||
if (false === iTopComposer::IsTestDir($sDir))
|
||||
{
|
||||
echo "\nfound INVALID denied test dir: '$sDir'\n";
|
||||
echo "ERROR found INVALID denied test dir: '$sDir'\n";
|
||||
throw new \Exception("$sDir must end with /Test/ or /test/");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SetupUtils::rrmdir($sDir);
|
||||
echo "Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
echo "\nFAILED to remove denied test dir: '$sDir'\n";
|
||||
if (false === file_exists($sDir)) {
|
||||
echo "INFO $sDir is in denied list, but not existing on disk => skipping !\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
SetupUtils::rrmdir($sDir);
|
||||
echo "OK Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
echo "\nFAILED to remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$aAllowedAndDeniedDirs = array_merge(
|
||||
$oiTopComposer->ListAllowedTestDir(),
|
||||
$oiTopComposer->ListDeniedTestDir()
|
||||
);
|
||||
$aExistingDirs = $oiTopComposer->ListAllTestDir();
|
||||
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
|
||||
if (false === empty($aMissing)) {
|
||||
echo "Some new tests dirs exists !\n"
|
||||
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
|
||||
.' List of dirs:'."\n".var_export($aMissing, true);
|
||||
}
|
||||
@@ -27,6 +27,7 @@ $aFilesUpdaters = array(
|
||||
new iTopVersionFileUpdater(),
|
||||
new CssVariablesFileUpdater(),
|
||||
new DatamodelsModulesFiles(),
|
||||
new ConstantFileUpdater('ITOP_CORE_VERSION', 'approot.inc.php'),
|
||||
);
|
||||
|
||||
if (count($argv) === 1)
|
||||
|
||||
@@ -69,6 +69,40 @@ abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714
|
||||
*/
|
||||
class ConstantFileUpdater extends AbstractSingleFileVersionUpdater {
|
||||
/** @var string */
|
||||
private $sConstantName;
|
||||
|
||||
/**
|
||||
* @param $sConstantName constant to search, for example `ITOP_CORE_VERSION`
|
||||
* @param $sFileToUpdate file containing constant definition
|
||||
*/
|
||||
public function __construct($sConstantName, $sFileToUpdate)
|
||||
{
|
||||
$this->sConstantName = $sConstantName;
|
||||
parent::__construct($sFileToUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
$sConstantSearchPattern = <<<REGEXP
|
||||
/define\('{$this->sConstantName}', ?'[^']+'\);/
|
||||
REGEXP;
|
||||
|
||||
return preg_replace(
|
||||
$sConstantSearchPattern,
|
||||
"define('{$this->sConstantName}', '{$sVersionLabel}');",
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
|
||||
@@ -111,9 +111,9 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)).
|
||||
Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
|
||||
Emoji examples :
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.dev/)).
|
||||
Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
|
||||
Emoji examples :
|
||||
* 🌐 `:globe_with_meridians:` for translations
|
||||
* 🎨 `:art:` when improving the format/structure of the code
|
||||
* ⚡️ `:zap:` when improving performance
|
||||
@@ -132,7 +132,7 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* squash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ define('PORTAL_PROFILE_NAME', 'Portal user');
|
||||
class UserRightsBaseClassGUI extends cmdbAbstractObject
|
||||
{
|
||||
// Whenever something changes, reload the privileges
|
||||
|
||||
|
||||
protected function AfterInsert()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
@@ -73,7 +73,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
}
|
||||
|
||||
protected static $m_aCacheProfiles = null;
|
||||
|
||||
|
||||
public static function DoCreateProfile($sName, $sDescription)
|
||||
{
|
||||
if (is_null(self::$m_aCacheProfiles))
|
||||
@@ -85,7 +85,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = $sName;
|
||||
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
|
||||
@@ -96,10 +96,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$oNewObj->Set('name', $sName);
|
||||
$oNewObj->Set('description', $sDescription);
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
|
||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
{
|
||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
@@ -116,7 +116,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
@@ -128,7 +128,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
||||
$oUserRights = UserRights::GetModuleInstance();
|
||||
|
||||
|
||||
$aDisplayData = array();
|
||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
|
||||
{
|
||||
@@ -137,12 +137,12 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
{
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
|
||||
|
||||
$aDisplayData[] = array(
|
||||
'class' => MetaModel::GetName($sClass),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||
@@ -154,7 +154,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$aDisplayConfig = array();
|
||||
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
|
||||
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
|
||||
@@ -214,7 +214,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
@@ -397,7 +397,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
{
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
||||
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oAddon = UserRights::GetModuleInstance();
|
||||
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
||||
if (count($aOrgs) > 0)
|
||||
@@ -521,7 +521,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
@@ -646,8 +646,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// load and cache permissions for the current user on the given class
|
||||
//
|
||||
$iUser = $oUser->GetKey();
|
||||
$aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
|
||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
}
|
||||
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
@@ -813,8 +815,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
/**
|
||||
* Find out which attribute is corresponding the the dimension 'owner org'
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
public static function GetOwnerOrganizationAttCode($sClass)
|
||||
{
|
||||
$sAttCode = null;
|
||||
|
||||
@@ -1083,11 +1083,11 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
/**
|
||||
* Implement this interface to add content to any enhanced portal page
|
||||
*
|
||||
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.4.0
|
||||
*
|
||||
* @since 2.4.0 interface creation
|
||||
* @since 2.7.0 change method signatures due to Silex to Symfony migration
|
||||
*/
|
||||
interface iPortalUIExtension
|
||||
{
|
||||
@@ -1160,7 +1160,11 @@ interface iPortalUIExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
|
||||
* Extend this class instead of iPortalUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.4.0
|
||||
*/
|
||||
abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
{
|
||||
|
||||
@@ -541,7 +541,7 @@ EOF
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$oPage->AddAjaxTab($oAttDef->GetLabel(), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='.get_class($this).'&id='.$this->GetKey().'&attcode='.$oAttDef->GetCode(), true, 'Class:'.$sClass.'/Attribute:'.$sAttCode);
|
||||
$oPage->AddAjaxTab( 'Class:'.$sClass.'/Attribute:'.$sAttCode, utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='.get_class($this).'&id='.$this->GetKey().'&attcode='.$oAttDef->GetCode(), true, $oAttDef->GetLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1557,6 +1557,9 @@ HTML
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* only used in old and deprecated export.php
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function DisplaySetAsHTMLSpreadsheet(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -1577,6 +1580,8 @@ HTML
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function GetSetAsHTMLSpreadsheet(DBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -4730,11 +4735,15 @@ EOF
|
||||
$sCSSClass = $bResult ? HILIGHT_CLASS_NONE : HILIGHT_CLASS_CRITICAL;
|
||||
$sChecked = $bResult ? 'checked' : '';
|
||||
$sDisabled = $bResult ? '' : 'disabled';
|
||||
|
||||
$aErrorsToDisplay = array_map(function($sError) {
|
||||
return utils::HtmlEntities($sError);
|
||||
}, $aErrors);
|
||||
$aRows[] = array(
|
||||
'form::select' => "<input type=\"checkbox\" class=\"selectList\" $sChecked $sDisabled\"></input>",
|
||||
'object' => $oObj->GetHyperlink(),
|
||||
'status' => $sStatus,
|
||||
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrors)).'</p>',
|
||||
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>',
|
||||
'@class' => $sCSSClass,
|
||||
);
|
||||
if ($bResult && (!$bPreview))
|
||||
|
||||
@@ -852,28 +852,29 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
|
||||
{
|
||||
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
|
||||
if (false === $sDashboardFileSanitized) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false)) {
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
if ($oUDSet->Count() > 0) {
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
|
||||
if ($sDashboardDefinition !== false)
|
||||
@@ -881,7 +882,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1477,6 +1478,29 @@ JS
|
||||
return $this->sDefinitionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDashboardFileRelative can also be an absolute path (compatibility with old URL)
|
||||
*
|
||||
* @return string full path to the Dashboard file
|
||||
* @throws \SecurityException if path isn't under approot
|
||||
* @uses utils::RealPath()
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°4449 remove FPD
|
||||
*/
|
||||
public static function GetDashboardFileFromRelativePath($sDashboardFileRelative)
|
||||
{
|
||||
if (utils::RealPath($sDashboardFileRelative, APPROOT)) {
|
||||
// compatibility with old URL containing absolute path !
|
||||
return $sDashboardFileRelative;
|
||||
}
|
||||
|
||||
$sDashboardFile = APPROOT.$sDashboardFileRelative;
|
||||
if (false === utils::RealPath($sDashboardFile, APPROOT)) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
return $sDashboardFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDefinitionFile
|
||||
*/
|
||||
|
||||
@@ -255,7 +255,7 @@ abstract class Dashlet
|
||||
catch(OqlException $e)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->p($e->GetUserFriendlyDescription());
|
||||
$oPage->p(utils::HtmlEntities($e->GetUserFriendlyDescription()));
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
catch(Exception $e)
|
||||
|
||||
@@ -324,8 +324,10 @@ class DisplayBlock
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 add type hinting to $aExtraParams
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams, $sId)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
// Add the extra params into the filter if they make sense for such a filter
|
||||
@@ -851,7 +853,7 @@ class DisplayBlock
|
||||
foreach($aStates as $sStateValue)
|
||||
{
|
||||
$sHtmlValue=$aGroupBy['group1']->MakeValueLabel($this->m_oFilter, $sStateValue, $sStateValue);
|
||||
$aStateLabels[$sStateValue] = html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8');
|
||||
$aStateLabels[$sStateValue] = strip_tags($sHtmlValue);
|
||||
|
||||
$aCounts[$sStateValue] = (array_key_exists($sStateValue, $aCountsQueryResults))
|
||||
? $aCountsQueryResults[$sStateValue]
|
||||
@@ -1418,8 +1420,25 @@ class HistoryBlock extends DisplayBlock
|
||||
$this->iLimitStart = $iStart;
|
||||
$this->iLimitCount = $iCount;
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param string $sId
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aExtraParams and add type hinting for PHP 8.0 compatibility
|
||||
* (var is unused, and all calls were already made using a default value)
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
$bTruncated = false;
|
||||
@@ -1558,8 +1577,10 @@ class MenuBlock extends DisplayBlock
|
||||
* @throws \Exception
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value and add type hinting on $aExtraParams for PHP 8.0 compatibility
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, $sId)
|
||||
{
|
||||
if ($this->m_sStyle == 'popup') // popup is a synonym of 'list' for backward compatibility
|
||||
{
|
||||
|
||||
@@ -1223,7 +1223,7 @@ class DesignerComboField extends DesignerFormField
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
|
||||
if ($this->IsSorted())
|
||||
if ($this->IsSorted() )
|
||||
{
|
||||
asort($this->aAllowedValues);
|
||||
}
|
||||
@@ -1271,18 +1271,14 @@ class DesignerComboField extends DesignerFormField
|
||||
$sHtml .= "<option value=\"\">".$this->sNullLabel."</option>";
|
||||
}
|
||||
}
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
foreach ($this->aAllowedValues as $sKey => $sDisplayValue) {
|
||||
if ($this->bMultipleSelection) {
|
||||
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8'));
|
||||
$sHtmlValue = str_replace(' ', ' ', $sDisplayValue);
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
$sHtml .= "</select>";
|
||||
|
||||
@@ -624,7 +624,7 @@ JS
|
||||
ShowDebug();
|
||||
$('#logOffBtn>ul').popupmenu();
|
||||
|
||||
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry,.caselog_entry_html').toggle(); });
|
||||
$('body').on('click', '.caselog_header', function () { $(this).toggleClass('open').next('.caselog_entry,.caselog_entry_html').toggle(); });
|
||||
|
||||
$(document).ajaxSend(function(event, jqxhr, options) {
|
||||
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
|
||||
|
||||
@@ -59,6 +59,8 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
// Save the checked user
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
@@ -67,7 +69,7 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
list($sAuthUser) = $this->GetAuthUserAndPassword();
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
|
||||
@@ -43,6 +43,8 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
// Save the checked user
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
@@ -51,7 +53,7 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'external')
|
||||
{
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'external', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
|
||||
@@ -71,6 +71,8 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
// Save the checked user
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
@@ -82,15 +84,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'form')
|
||||
{
|
||||
if (isset($_SESSION['auth_user']))
|
||||
{
|
||||
// If FSM reenter this state (example 2FA) then the auth_user is not resubmitted
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
|
||||
}
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
// Store 'auth_user' in session for further use
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
// Save the checked user
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
@@ -66,7 +68,7 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
|
||||
@@ -208,7 +208,7 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
// This token allows the user to change the password without knowing the previous one
|
||||
$sToken = substr(md5(APPROOT.uniqid()), 0, 16);
|
||||
$sToken = bin2hex(random_bytes(32));
|
||||
$oUser->Set('reset_pwd_token', $sToken);
|
||||
CMDBObject::SetTrackInfo('Reset password');
|
||||
$oUser->AllowWrite(true);
|
||||
|
||||
@@ -35,29 +35,25 @@ register_shutdown_function(function()
|
||||
$sReservedMemory = null;
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
|
||||
{
|
||||
// Remove stack trace from MySQLException
|
||||
// Remove stack trace from MySQLException (since 2.7.2 see N°3174)
|
||||
$sMessage = $err['message'];
|
||||
if (strpos($sMessage, 'MySQLException') !== false)
|
||||
{
|
||||
if (strpos($sMessage, 'MySQLException') !== false) {
|
||||
$iStackTracePos = strpos($sMessage, 'Stack trace:');
|
||||
if ($iStackTracePos !== false)
|
||||
{
|
||||
if ($iStackTracePos !== false) {
|
||||
$sMessage = substr($sMessage, 0, $iStackTracePos);
|
||||
}
|
||||
}
|
||||
IssueLog::error($sMessage, null, $err);
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false)
|
||||
{
|
||||
// Log additional info but message from $err (since 2.7.6 N°4174)
|
||||
$aErrToLog = $err;
|
||||
unset($aErrToLog['message']);
|
||||
IssueLog::error($sMessage, null, $aErrToLog);
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false) {
|
||||
$sLimit = ini_get('memory_limit');
|
||||
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase 'memory_limit' in php.ini</p>\n";
|
||||
}
|
||||
elseif (strpos($err['message'], 'Maximum execution time') !== false)
|
||||
{
|
||||
} elseif (strpos($err['message'], 'Maximum execution time') !== false) {
|
||||
$sLimit = ini_get('max_execution_time');
|
||||
echo "<p>iTop: Maximum execution time of $sLimit exceeded, contact your administrator to increase 'max_execution_time' in php.ini</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class privUITransaction
|
||||
{
|
||||
/**
|
||||
@@ -99,9 +97,10 @@ class privUITransaction
|
||||
}
|
||||
|
||||
/**
|
||||
* The original (and by default) mechanism for storing transaction information
|
||||
* as an array in the $_SESSION variable
|
||||
* The original mechanism for storing transaction information as an array in the $_SESSION variable
|
||||
*
|
||||
* Warning, since 2.6.0 the session is regenerated on each login (see PR #20) !
|
||||
* Also, we saw some problems when using memcached as the PHP session implementation (see N°1835)
|
||||
*/
|
||||
class privUITransactionSession
|
||||
{
|
||||
@@ -194,9 +193,35 @@ class privUITransactionSession
|
||||
*/
|
||||
class privUITransactionFile
|
||||
{
|
||||
/** @var int Value to use when no user logged */
|
||||
const UNAUTHENTICATED_USER_ID = -666;
|
||||
|
||||
/**
|
||||
* @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 method creation
|
||||
*/
|
||||
private static function GetCurrentUserId()
|
||||
{
|
||||
$iCurrentUserId = UserRights::GetConnectedUserId();
|
||||
if ('' === $iCurrentUserId) {
|
||||
$iCurrentUserId = static::UNAUTHENTICATED_USER_ID;
|
||||
}
|
||||
|
||||
return $iCurrentUserId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transaction id, store it in the session and return its id
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return int The new transaction identifier
|
||||
*
|
||||
* @throws \SecurityException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 security hardening + throws SecurityException if no user logged
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
@@ -213,24 +238,36 @@ class privUITransactionFile
|
||||
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(APPROOT.'data/transactions'))
|
||||
{
|
||||
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
|
||||
}
|
||||
self::CleanupOldTransactions();
|
||||
$id = basename(tempnam(APPROOT.'data/transactions', static::GetUserPrefix()));
|
||||
self::Info('GetNewTransactionId: Created transaction: '.$id);
|
||||
|
||||
return (string)$id;
|
||||
$iCurrentUserId = static::GetCurrentUserId();
|
||||
|
||||
self::CleanupOldTransactions();
|
||||
|
||||
$sTransactionIdFullPath = tempnam(APPROOT.'data/transactions', static::GetUserPrefix());
|
||||
file_put_contents($sTransactionIdFullPath, $iCurrentUserId, LOCK_EX);
|
||||
|
||||
$sTransactionIdFileName = basename($sTransactionIdFullPath);
|
||||
self::Info('GetNewTransactionId: Created transaction: '.$sTransactionIdFileName);
|
||||
|
||||
return $sTransactionIdFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
|
||||
* the session so that another call to IsTransactionValid for the same transaction id
|
||||
* will return false
|
||||
*
|
||||
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
|
||||
* @param bool $bRemoveTransaction True if the transaction must be removed
|
||||
*
|
||||
* @return bool True if the transaction is valid, false otherwise
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
|
||||
*/
|
||||
public static function IsTransactionValid($id, $bRemoveTransaction = true)
|
||||
{
|
||||
@@ -244,53 +281,53 @@ class privUITransactionFile
|
||||
|
||||
clearstatcache(true, $sFilepath);
|
||||
$bResult = file_exists($sFilepath);
|
||||
if ($bResult)
|
||||
|
||||
if (false === $bResult) {
|
||||
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
|
||||
$iCurrentUserId = static::GetCurrentUserId();
|
||||
$sTransactionIdUserId = file_get_contents($sFilepath);
|
||||
if ($iCurrentUserId != $sTransactionIdUserId) {
|
||||
self::Info("IsTransactionValid: Transaction '$id' not existing for current user. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($bRemoveTransaction)
|
||||
{
|
||||
if ($bRemoveTransaction)
|
||||
$bResult = @unlink($sFilepath);
|
||||
if (!$bResult)
|
||||
{
|
||||
$bResult = @unlink($sFilepath);
|
||||
if (!$bResult)
|
||||
{
|
||||
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
|
||||
}
|
||||
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the transaction specified by its id
|
||||
* @param int $id The Identifier (as returned by GetNewTransactionId) of the transaction to be removed.
|
||||
* @return void
|
||||
* @return bool true if the token can be removed
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
|
||||
*/
|
||||
public static function RemoveTransaction($id)
|
||||
{
|
||||
$bSuccess = true;
|
||||
$sFilepath = APPROOT.'data/transactions/'.$id;
|
||||
clearstatcache(true, $sFilepath);
|
||||
if(!file_exists($sFilepath))
|
||||
{
|
||||
$bSuccess = false;
|
||||
self::Error("RemoveTransaction: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$bResult = static::IsTransactionValid($id, true);
|
||||
if (false === $bResult) {
|
||||
self::Error("RemoveTransaction: Transaction '$id' is invalid. Pending transactions:\n"
|
||||
.implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
$bSuccess = @unlink($sFilepath);
|
||||
if (!$bSuccess)
|
||||
{
|
||||
self::Error('RemoveTransaction: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('RemoveTransaction: OK '.$id);
|
||||
}
|
||||
return $bSuccess;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,22 +400,35 @@ class privUITransactionFile
|
||||
{
|
||||
self::Write('Error | '.$sText);
|
||||
}
|
||||
|
||||
|
||||
protected static function IsLogEnabled() {
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
if (is_null($oConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bLogTransactions = $oConfig->Get('log_transactions');
|
||||
if (true === $bLogTransactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static function Write($sText)
|
||||
{
|
||||
$bLogEnabled = MetaModel::GetConfig()->Get('log_transactions');
|
||||
if ($bLogEnabled)
|
||||
{
|
||||
if (false === static::IsLogEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hLogFile = @fopen(APPROOT.'log/transactions.log', 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
if ($hLogFile !== false) {
|
||||
flock($hLogFile, LOCK_EX);
|
||||
$sDate = date('Y-m-d H:i:s');
|
||||
fwrite($hLogFile, "$sDate | $sText\n");
|
||||
fflush($hLogFile);
|
||||
flock($hLogFile, LOCK_UN);
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Combodo\iTop;
|
||||
use AttributeDateTime;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use Twig_Environment;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
@@ -115,14 +114,6 @@ class TwigExtension
|
||||
return utils::IsDevelopmentEnvironment();
|
||||
}));
|
||||
|
||||
// Function to get configuration parameter
|
||||
// Usage in twig: {{ get_config_parameter('foo') }}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_config_parameter', function($sParamName)
|
||||
{
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
return $oConfig->Get($sParamName);
|
||||
}));
|
||||
|
||||
// Function to get the URL of a static page in a module
|
||||
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_static_page_module_url', function($sModuleName, $sPage)
|
||||
|
||||
@@ -71,7 +71,11 @@ class UIExtKeyWidget
|
||||
protected $bSearchMode;
|
||||
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
|
||||
|
||||
/**
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
|
||||
*/
|
||||
public static function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs = [], $bSearchMode = false)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
@@ -372,10 +376,10 @@ EOF
|
||||
$sHTML .= "</form>\n";
|
||||
$sHTML .= '</div></div>';
|
||||
|
||||
$sDialogTitle = addslashes($sTitle);
|
||||
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
|
||||
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitleSanitized', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
|
||||
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
|
||||
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
|
||||
EOF
|
||||
@@ -426,8 +430,10 @@ EOF
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
|
||||
{
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
|
||||
@@ -85,9 +85,15 @@ class UILinksWidgetDirect
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (handling wrong values at method start)
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
if (empty($aArgs)) {
|
||||
$aArgs = [];
|
||||
}
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
@@ -137,8 +143,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, always called with default value)
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
@@ -239,8 +247,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, caller already handles it)
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
|
||||
@@ -283,6 +283,7 @@ class utils
|
||||
*
|
||||
* @since 2.5.2 2.6.0 new 'transaction_id' filter
|
||||
* @since 2.7.0 new 'element_identifier' filter
|
||||
* @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter
|
||||
*/
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
@@ -358,6 +359,11 @@ class utils
|
||||
$retValue = preg_replace('/[^a-zA-Z0-9_]/', '', $value);
|
||||
break;
|
||||
|
||||
// For URL
|
||||
case 'url':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_URL);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
$retValue = $value;
|
||||
@@ -1323,19 +1329,19 @@ class utils
|
||||
$oDashboard = $param;
|
||||
$sDashboardId = $oDashboard->GetId();
|
||||
$sDashboardFile = $oDashboard->GetDefinitionFile();
|
||||
$sDashboardFileRelative = utils::LocalPath($sDashboardFile);
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$sDashboardFileJS = addslashes($sDashboardFile);
|
||||
$sDashboardFileURL = urlencode($sDashboardFile);
|
||||
$sDashboardFileJS = addslashes($sDashboardFileRelative);
|
||||
$sDashboardFileURL = urlencode($sDashboardFileRelative);
|
||||
$sUploadDashboardTransactId = utils::GetNewTransactionId();
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
|
||||
);
|
||||
if ($oDashboard->GetReloadURL())
|
||||
{
|
||||
if ($oDashboard->GetReloadURL()) {
|
||||
$aResult[] = new SeparatorPopupMenuItem();
|
||||
$aResult[] = new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $oDashboard->GetReloadURL().'&printable=1', '_blank');
|
||||
}
|
||||
@@ -1960,11 +1966,15 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @param number $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
* @return string
|
||||
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
|
||||
*
|
||||
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
*
|
||||
* @return string the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
*
|
||||
* @uses \debug_backtrace()
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
@@ -1989,9 +1999,14 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* **Warning** : as this method uses {@see GetCurrentModuleDir} it produces hazardous results.
|
||||
* You should better uses directly {@see GetAbsoluteUrlModulesRoot} and add the module dir name yourself ! See N°4573
|
||||
*
|
||||
* @return string the base URL for all files in the current module from which this method is called
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @throws \Exception
|
||||
*
|
||||
* @uses GetCurrentModuleDir
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
@@ -2246,38 +2261,19 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
|
||||
* @return string eg : '2_7_0' if iTop core version is '2.7.5-2'
|
||||
* @throws \ApplicationException if constant value is invalid
|
||||
* @uses ITOP_CORE_VERSION
|
||||
*/
|
||||
public static function GetItopVersionWikiSyntax()
|
||||
public static function GetItopVersionWikiSyntax($sItopVersion = ITOP_CORE_VERSION)
|
||||
{
|
||||
$sMinorVersion = self::GetItopMinorVersion();
|
||||
return str_replace('.', '_', $sMinorVersion).'_0';
|
||||
}
|
||||
$aExplodedVersion = explode('.', $sItopVersion);
|
||||
|
||||
/**
|
||||
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetItopMinorVersion()
|
||||
{
|
||||
$sPatchVersion = self::GetItopPatchVersion();
|
||||
$aExplodedVersion = explode('.', $sPatchVersion);
|
||||
|
||||
if (empty($aExplodedVersion[0]) || empty($aExplodedVersion[1]))
|
||||
{
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
if ((false === isset($aExplodedVersion[0])) || (false === isset($aExplodedVersion[1]))) {
|
||||
throw new ApplicationException('iTop version is wrongfully configured!');
|
||||
}
|
||||
|
||||
return sprintf('%d.%d', $aExplodedVersion[0], $aExplodedVersion[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
|
||||
*/
|
||||
public static function GetItopPatchVersion()
|
||||
{
|
||||
$aExplodedVersion = explode('-', ITOP_VERSION);
|
||||
return $aExplodedVersion[0];
|
||||
return "{$aExplodedVersion[0]}_{$aExplodedVersion[1]}_0";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,4 +3,18 @@
|
||||
define('APPROOT', dirname(__FILE__).'/');
|
||||
define('APPCONF', APPROOT.'conf/');
|
||||
|
||||
|
||||
/**
|
||||
* Constant containing the iTop core version, whatever application was built
|
||||
*
|
||||
* Note that in iTop 3.0.0 we used {@see ITOP_DESIGN_LATEST_VERSION} to get core version.
|
||||
* When releasing, both constants should be updated : see `.make/release/update-versions.php` for that !
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714 constant creation
|
||||
* @used-by utils::GetItopVersionWikiSyntax()
|
||||
* @used-by iTopModulesPhpVersionIntegrationTest
|
||||
*/
|
||||
define('ITOP_CORE_VERSION', '2.7.8');
|
||||
|
||||
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"name": "combodo/itop",
|
||||
"description": "IT Operations Portal",
|
||||
"type": "project",
|
||||
"license": "AGPLv3",
|
||||
"license": "AGPL-3.0-only",
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"php": ">=7.0.8",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -10,22 +12,27 @@
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"combodo/tcpdf": "6.3.5",
|
||||
"nikic/php-parser": "^3.1",
|
||||
"pear/archive_tar": "1.4.13",
|
||||
"pelago/emogrifier": "2.1.0",
|
||||
"combodo/tcpdf": "~6.4.4",
|
||||
"guzzlehttp/guzzle": "^6.5.8",
|
||||
"laminas/laminas-mail": "^2.11",
|
||||
"laminas/laminas-servicemanager": "^3.5",
|
||||
"league/oauth2-google": "^3.0",
|
||||
"nikic/php-parser": "~4.13.2",
|
||||
"pear/archive_tar": "~1.4.14",
|
||||
"pelago/emogrifier": "~3.1.0",
|
||||
"scssphp/scssphp": "1.0.6",
|
||||
"swiftmailer/swiftmailer": "5.4.12",
|
||||
"symfony/console": "3.4.*",
|
||||
"symfony/dotenv": "3.4.*",
|
||||
"symfony/framework-bundle": "3.4.*",
|
||||
"symfony/polyfill-php70": "1.*",
|
||||
"symfony/twig-bundle": "3.4.*",
|
||||
"symfony/yaml": "3.4.*"
|
||||
"swiftmailer/swiftmailer": "~6.3.0",
|
||||
"symfony/console": "~3.4.47",
|
||||
"symfony/dotenv": "~3.4.47",
|
||||
"symfony/framework-bundle": "~3.4.47",
|
||||
"symfony/twig-bundle": "~3.4.47",
|
||||
"symfony/yaml": "~3.4.47",
|
||||
"thenetworg/oauth2-azure": "^2.0",
|
||||
"twig/twig": "~1.42.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "3.4.*",
|
||||
"symfony/web-profiler-bundle": "3.4.*"
|
||||
"symfony/stopwatch": "~3.4.47",
|
||||
"symfony/web-profiler-bundle": "~3.4.47"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
@@ -37,7 +44,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
"php": "7.0.8"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
@@ -52,7 +59,8 @@
|
||||
"application",
|
||||
"sources/application",
|
||||
"sources/Composer",
|
||||
"sources/Controller"
|
||||
"sources/Controller",
|
||||
"sources/Core"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"core/dbobjectsearch.class.php",
|
||||
|
||||
2838
composer.lock
generated
2838
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -179,7 +179,7 @@ class ActionEmail extends ActionNotification
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (strlen($sOQL) == '') return '';
|
||||
if (strlen($sOQL) === 0) return '';
|
||||
|
||||
try
|
||||
{
|
||||
@@ -314,42 +314,58 @@ class ActionEmail extends ActionNotification
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
$bRes = false; // until we do succeed in sending the email
|
||||
|
||||
|
||||
// Determine recicipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
|
||||
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
|
||||
$sMessageId = sprintf('iTop_%s_%d_%F@%s.openitop.org',
|
||||
get_class($oObj),
|
||||
$oObj->GetKey(),
|
||||
microtime(true /* get as float*/),
|
||||
MetaModel::GetEnvironmentId()
|
||||
);
|
||||
$sReference = '<'.$sMessageId.'>';
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
throw $e;
|
||||
}
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
|
||||
if (!is_null($oLog))
|
||||
{
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
if (isset($sTo)) $oLog->Set('to', $sTo);
|
||||
if (isset($sCC)) $oLog->Set('cc', $sCC);
|
||||
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
|
||||
if (isset($sFrom)) $oLog->Set('from', $sFrom);
|
||||
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
if (isset($sTo)) {
|
||||
$oLog->Set('to', $sTo);
|
||||
}
|
||||
if (isset($sCC)) {
|
||||
$oLog->Set('cc', $sCC);
|
||||
}
|
||||
if (isset($sBCC)) {
|
||||
$oLog->Set('bcc', $sBCC);
|
||||
}
|
||||
if (isset($sFrom)) {
|
||||
$oLog->Set('from', $sFrom);
|
||||
}
|
||||
if (isset($sSubject)) {
|
||||
$oLog->Set('subject', $sSubject);
|
||||
}
|
||||
if (isset($sBody)) {
|
||||
$oLog->Set('body', $sBody);
|
||||
}
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
@@ -439,4 +455,3 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
42
core/apc-service.class.inc.php
Normal file
42
core/apc-service.class.inc.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ApcService
|
||||
* @since 2.7.6 N°4125
|
||||
*/
|
||||
class ApcService {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function_name
|
||||
* @return bool
|
||||
* @see function_exists()
|
||||
*/
|
||||
public function function_exists($function_name) {
|
||||
return function_exists($function_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $key
|
||||
* @return mixed
|
||||
* @see apc_fetch()
|
||||
*/
|
||||
function apc_fetch($key)
|
||||
{
|
||||
return apc_fetch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $key
|
||||
* @param $var
|
||||
* @param int $ttl
|
||||
* @return array|bool
|
||||
* @see apc_store()
|
||||
*/
|
||||
function apc_store($key, $var = NULL, $ttl = 0)
|
||||
{
|
||||
return apc_store($key, $var, $ttl);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -230,7 +230,7 @@ abstract class AsyncTask extends DBObject
|
||||
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
|
||||
}
|
||||
|
||||
$this->Set('last_error', $sErrorMessage);
|
||||
$this->SetTrim('last_error', $sErrorMessage);
|
||||
$this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!!
|
||||
$this->Set('last_attempt', time());
|
||||
|
||||
|
||||
@@ -7978,6 +7978,13 @@ class AttributeImage extends AttributeBlob
|
||||
{
|
||||
$oDoc = parent::MakeRealValue($proposedValue, $oHostObj);
|
||||
|
||||
if (($oDoc instanceof ormDocument)
|
||||
&& (false === $oDoc->IsEmpty())
|
||||
&& ($oDoc->GetMimeType() === 'image/svg+xml')) {
|
||||
$sCleanSvg = HTMLSanitizer::Sanitize($oDoc->GetData(), 'svg_sanitizer');
|
||||
$oDoc = new ormDocument($sCleanSvg, $oDoc->GetMimeType(), $oDoc->GetFileName());
|
||||
}
|
||||
|
||||
// The validation of the MIME Type is done by CheckFormat below
|
||||
return $oDoc;
|
||||
}
|
||||
|
||||
@@ -63,22 +63,30 @@ class CMDBChangeOp extends DBObject
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Safety net: in case the change is not given, let's guarantee that it will
|
||||
* be set to the current ongoing change (or create a new one)
|
||||
*/
|
||||
* Safety net:
|
||||
* * if change isn't persisted yet, use the current change and persist it if needed
|
||||
* * in case the change is not given, let's guarantee that it will be set to the current ongoing change (or create a new one)
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 do persist the current change if needed
|
||||
*/
|
||||
protected function OnInsert()
|
||||
{
|
||||
if ($this->Get('change') <= 0)
|
||||
{
|
||||
$this->Set('change', CMDBObject::GetCurrentChange());
|
||||
$iChange = $this->Get('change');
|
||||
if (($iChange <= 0) || (is_null($iChange))) {
|
||||
$oChange = CMDBObject::GetCurrentChange();
|
||||
if ($oChange->IsNew()) {
|
||||
$oChange->DBWrite();
|
||||
}
|
||||
$this->Set('change', $oChange);
|
||||
}
|
||||
|
||||
parent::OnInsert();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,26 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_oCurrChange = $oChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sUserInfo
|
||||
* @param string $sOrigin
|
||||
* @param \DateTime $oDate
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 new method to reset current change
|
||||
*/
|
||||
public static function SetCurrentChangeFromParams($sUserInfo, $sOrigin = null, $oDate = null)
|
||||
{
|
||||
static::SetTrackInfo($sUserInfo);
|
||||
static::SetTrackOrigin($sOrigin);
|
||||
static::CreateChange();
|
||||
|
||||
if (!is_null($oDate)) {
|
||||
static::$m_oCurrChange->Set("date", $oDate);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Todo: simplify the APIs and do not pass the current change as an argument anymore
|
||||
// SetTrackInfo to be invoked in very few cases (UI.php, CSV import, Data synchro)
|
||||
@@ -145,6 +165,8 @@ abstract class CMDBObject extends DBObject
|
||||
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
|
||||
* $iChangeId = $oMyChange->DBInsert();
|
||||
*
|
||||
* **warning** : this will do nothing if current change already exists !
|
||||
*
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
* @param string $sInfo
|
||||
@@ -157,6 +179,8 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* Provides information about the origin of the change
|
||||
*
|
||||
* **warning** : this will do nothing if current change already exists !
|
||||
*
|
||||
* @see SetTrackInfo
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
@@ -167,18 +191,15 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
self::$m_sOrigin = $sOrigin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the additional information (defaulting to user name)
|
||||
*/
|
||||
protected static function GetTrackInfo()
|
||||
*/
|
||||
public static function GetTrackInfo()
|
||||
{
|
||||
if (is_null(self::$m_sInfo))
|
||||
{
|
||||
if (is_null(self::$m_sInfo)) {
|
||||
return CMDBChange::GetCurrentUserName();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return self::$m_sInfo;
|
||||
}
|
||||
}
|
||||
@@ -201,7 +222,8 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* Set to {@link $m_oCurrChange} a standard change record (done here 99% of the time, and nearly once per page)
|
||||
*
|
||||
* The CMDBChange is persisted so that it has a key > 0, and any new CMDBChangeOp can link to it
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 {@see CMDBChange} **will be persisted later** in {@see \CMDBChangeOp::OnInsert} (was done previously directly here)
|
||||
* This will avoid creating in DB CMDBChange lines without any corresponding CMDBChangeOp
|
||||
*/
|
||||
protected static function CreateChange()
|
||||
{
|
||||
@@ -209,7 +231,6 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_oCurrChange->Set("date", time());
|
||||
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
|
||||
self::$m_oCurrChange->Set("origin", self::GetTrackOrigin());
|
||||
self::$m_oCurrChange->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -113,10 +113,18 @@ class MySQLNoTransactionException extends MySQLException
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°5538
|
||||
*/
|
||||
class MySQLTransactionNotClosedException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CMDBSource
|
||||
* database access wrapper
|
||||
* database access wrapper
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
@@ -154,6 +162,16 @@ class CMDBSource
|
||||
|
||||
/** @var mysqli $m_oMysqli */
|
||||
protected static $m_oMysqli;
|
||||
/**
|
||||
* The mysqli object is really hard to mock ! This attribute is used only in certain methods, so that we can mock only a very little subset of the mysqli object.
|
||||
* We are setting it in {@see Init}, by default it is a copy of {@see $m_oMysqli}
|
||||
* The mock can be injected using the setter {@see SetMySQLiForQuery}
|
||||
*
|
||||
* @var mysqli $oMySQLiForQuery
|
||||
* @see GetMySQLiForQuery
|
||||
* @see SetMySQLiForQuery
|
||||
* @since 2.7.5 N°3513 new var to allow mock in tests ({@see \Combodo\iTop\Test\UnitTest\Core\TransactionsTest})
|
||||
*/
|
||||
protected static $oMySQLiForQuery;
|
||||
|
||||
/**
|
||||
@@ -235,6 +253,8 @@ class CMDBSource
|
||||
*
|
||||
* @return \mysqli
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses IsOpenedDbConnectionUsingTls when asking for a TLS connection, to check if it was really opened using TLS
|
||||
*/
|
||||
public static function GetMysqliInstance(
|
||||
$sDbHost, $sUser, $sPwd, $sSource = '', $bTlsEnabled = false, $sTlsCa = null, $bCheckTlsAfterConnection = false
|
||||
@@ -337,41 +357,41 @@ class CMDBSource
|
||||
* parameters were used.<br>
|
||||
* This method can be called to ensure that the DB connection really uses TLS.
|
||||
*
|
||||
* <p>We're using this object connection : {@link self::$m_oMysqli}
|
||||
* <p>We're using our own mysqli instance to do the check as this check is done when creating the mysqli instance : the consumer
|
||||
* might want a dedicated object, and if so we don't want to overwrite the one saved in CMDBSource !<br>
|
||||
* This is the case for example with {@see \iTopMutex} !
|
||||
*
|
||||
* @param \mysqli $oMysqli
|
||||
*
|
||||
* @return boolean true if the connection was really established using TLS
|
||||
* @return boolean true if the connection was really established using TLS, false otherwise
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @used-by GetMysqliInstance
|
||||
* @uses IsMySqlVarNonEmpty
|
||||
* @uses 'ssl_version' MySQL var
|
||||
* @uses 'ssl_cipher' MySQL var
|
||||
*/
|
||||
private static function IsOpenedDbConnectionUsingTls($oMysqli)
|
||||
{
|
||||
if (self::$m_oMysqli == null)
|
||||
{
|
||||
self::$m_oMysqli = $oMysqli;
|
||||
}
|
||||
|
||||
$bNonEmptySslVersionVar = self::IsMySqlVarNonEmpty('ssl_version');
|
||||
$bNonEmptySslCipherVar = self::IsMySqlVarNonEmpty('ssl_cipher');
|
||||
$bNonEmptySslVersionVar = self::IsMySqlVarNonEmpty('ssl_version', $oMysqli);
|
||||
$bNonEmptySslCipherVar = self::IsMySqlVarNonEmpty('ssl_cipher', $oMysqli);
|
||||
|
||||
return ($bNonEmptySslVersionVar && $bNonEmptySslCipherVar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sVarName
|
||||
* @param mysqli $oMysqli connection to use for the query
|
||||
*
|
||||
* @return bool
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses SHOW STATUS queries
|
||||
* @uses 'SHOW SESSION STATUS' queries
|
||||
*/
|
||||
private static function IsMySqlVarNonEmpty($sVarName)
|
||||
private static function IsMySqlVarNonEmpty($sVarName, $oMysqli)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sResult = self::QueryToScalar("SHOW SESSION STATUS LIKE '$sVarName'", 1);
|
||||
$sResult = self::QueryToScalar("SHOW SESSION STATUS LIKE '$sVarName'", 1, $oMysqli);
|
||||
}
|
||||
catch (MySQLQueryHasNoResultException $e)
|
||||
{
|
||||
@@ -435,6 +455,12 @@ class CMDBSource
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses \CMDBSource::QueryToCol() so needs a connection opened !
|
||||
*/
|
||||
public static function GetDBVersion()
|
||||
{
|
||||
$aVersions = self::QueryToCol('SELECT Version() as version', 'version');
|
||||
@@ -452,8 +478,10 @@ class CMDBSource
|
||||
/**
|
||||
* Get the DB vendor between MySQL and its main forks
|
||||
* @return string
|
||||
*
|
||||
* @uses \CMDBSource::GetServerVariable() so needs a connection opened !
|
||||
*/
|
||||
static public function GetDBVendor()
|
||||
public static function GetDBVendor()
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
|
||||
|
||||
@@ -709,7 +737,7 @@ class CMDBSource
|
||||
{
|
||||
$aContext = array('query' => $sSql);
|
||||
|
||||
$iMySqlErrorNo = self::$m_oMysqli->errno;
|
||||
$iMySqlErrorNo = self::GetMySQLiForQuery()->errno;
|
||||
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();
|
||||
if (in_array($iMySqlErrorNo, $aMySqlHasGoneAwayErrorCodes))
|
||||
{
|
||||
@@ -731,7 +759,7 @@ class CMDBSource
|
||||
private static function LogDeadLock(Exception $e)
|
||||
{
|
||||
// checks MySQL error code
|
||||
$iMySqlErrorNo = self::$m_oMysqli->errno;
|
||||
$iMySqlErrorNo = self::GetMySQLiForQuery()->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK)))
|
||||
{
|
||||
return;
|
||||
@@ -739,7 +767,7 @@ class CMDBSource
|
||||
|
||||
// Get error info
|
||||
$sUser = UserRights::GetUser();
|
||||
$oError = self::$m_oMysqli->query('SHOW ENGINE INNODB STATUS');
|
||||
$oError = self::GetMySQLiForQuery()->query('SHOW ENGINE INNODB STATUS');
|
||||
if ($oError !== false)
|
||||
{
|
||||
$aData = $oError->fetch_all(MYSQLI_ASSOC);
|
||||
@@ -778,14 +806,14 @@ class CMDBSource
|
||||
private static function StartTransaction()
|
||||
{
|
||||
$aStackTrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT , 3);
|
||||
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
|
||||
|
||||
$bHasExistingTransactions = self::IsInsideTransaction();
|
||||
if (!$bHasExistingTransactions)
|
||||
{
|
||||
IssueLog::Trace("START TRANSACTION $sCaller", 'cmdbsource');
|
||||
IssueLog::Trace("START TRANSACTION was sent to the DB", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
self::DBQuery('START TRANSACTION');
|
||||
} else {
|
||||
IssueLog::Trace("Ignore nested (".self::$m_iTransactionLevel.") START TRANSACTION $sCaller", 'cmdbsource');
|
||||
IssueLog::Trace("START TRANSACTION ignored as a transaction is already opened", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
}
|
||||
|
||||
self::AddTransactionLevel();
|
||||
@@ -967,17 +995,21 @@ class CMDBSource
|
||||
/**
|
||||
* @param string $sSql
|
||||
* @param int $iCol beginning at 0
|
||||
* @param mysqli $oMysqli if not null will query using this connection, otherwise will use {@see GetMySQLiForQuery}
|
||||
*
|
||||
* @return string corresponding cell content on the first line
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLQueryHasNoResultException
|
||||
* @since 2.7.5-2 2.7.6 3.0.0 N°4215 new optional mysqli param
|
||||
*/
|
||||
public static function QueryToScalar($sSql, $iCol = 0)
|
||||
public static function QueryToScalar($sSql, $iCol = 0, $oMysqli = null)
|
||||
{
|
||||
$oMysqliToQuery = (is_null($oMysqli)) ? self::GetMySQLiForQuery() : $oMysqli;
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
try
|
||||
{
|
||||
$oResult = self::GetMySQLiForQuery()->query($sSql);
|
||||
$oResult = $oMysqliToQuery->query($sSql);
|
||||
}
|
||||
catch(mysqli_sql_exception $e)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,15 @@
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '2.7.0-dev'); // @see utils::GetItopVersionShort() and utils::GetItopVersionWikiSyntax()
|
||||
|
||||
/**
|
||||
* Constant containing the application version
|
||||
* Warning: this might be different from iTop core version!
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '2.7.0-dev');
|
||||
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
define('ITOP_VERSION_FULL', ITOP_VERSION.'-'.ITOP_REVISION);
|
||||
@@ -468,11 +476,11 @@ class Config
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cron_max_execution_time' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
|
||||
'default' => 600,
|
||||
'value' => 600,
|
||||
'source_of_value' => '',
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) of the cron.php script : if exceeded the script will exit even if there are remaining tasks to process. Must be shorter than php max_execution_time setting (note than when using CLI, this is set to 0 by default which means unlimited). If cron.php is ran via web, it must be shorter than the web server response timeout.',
|
||||
'default' => 600,
|
||||
'value' => 600,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cron_sleep' => array(
|
||||
@@ -501,7 +509,7 @@ class Config
|
||||
),
|
||||
'email_transport' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)',
|
||||
'description' => 'Mean to send emails: PHPMail (uses the function mail()), SMTP (implements the client protocol) or SMTP_OAuth (connect to the server using OAuth 2.0)',
|
||||
'default' => "PHPMail",
|
||||
'value' => "PHPMail",
|
||||
'source_of_value' => '',
|
||||
@@ -547,6 +555,22 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.allow_self_signed' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Allow self signed peer certificates',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.verify_peer' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Verify peer certificate',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_css' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
@@ -595,6 +619,13 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
/**
|
||||
* The timezone is automatically set using this parameter in \utils::InitTimeZone
|
||||
* This method is called almost everywhere, cause it's called in \MetaModel::LoadConfig and exec.php... but you might
|
||||
* need to get it yourself !
|
||||
*
|
||||
* @used-by utils::InitTimeZone()
|
||||
*/
|
||||
'timezone' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP',
|
||||
@@ -838,6 +869,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'impact_analysis_lazy_loading' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'In the impact analysis view: display the analysis or filter before display',
|
||||
'default' => false,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'url_validation_pattern' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
|
||||
@@ -1113,6 +1152,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'svg_sanitizer' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The class to use for SVG sanitization : allow to provide a custom made sanitizer',
|
||||
'default' => 'SVGDOMSanitizer',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'inline_image_max_display_width' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.',
|
||||
@@ -1273,6 +1320,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'security.disable_inline_documents_sandbox' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -165,19 +165,15 @@ class CoreCannotSaveObjectException extends CoreException
|
||||
public function getHtmlMessage()
|
||||
{
|
||||
$sTitle = Dict::S('UI:Error:SaveFailed');
|
||||
$sContent = "<span><strong>{$sTitle}</strong></span>";
|
||||
$sContent = "<span><strong>".utils::HtmlEntities($sTitle)."</strong></span>";
|
||||
|
||||
if (count($this->aIssues) == 1)
|
||||
{
|
||||
if (count($this->aIssues) == 1) {
|
||||
$sIssue = reset($this->aIssues);
|
||||
$sContent .= " <span>{$sIssue}</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sContent .= " <span>".utils::HtmlEntities($sIssue)."</span>";
|
||||
} else {
|
||||
$sContent .= '<ul>';
|
||||
foreach ($this->aIssues as $sError)
|
||||
{
|
||||
$sContent .= "<li>$sError</li>";
|
||||
foreach ($this->aIssues as $sError) {
|
||||
$sContent .= "<li>".utils::HtmlEntities($sError)."</li>";
|
||||
}
|
||||
$sContent .= '</ul>';
|
||||
}
|
||||
|
||||
@@ -1977,9 +1977,9 @@ abstract class DBObject implements iDisplay
|
||||
/**
|
||||
* check attributes together
|
||||
*
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
*
|
||||
* @return bool
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
*
|
||||
* @return true|string true if successful, the error description otherwise
|
||||
*/
|
||||
public function CheckConsistency()
|
||||
{
|
||||
@@ -3690,7 +3690,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
|
||||
@@ -416,6 +416,10 @@ class DBObjectSearch extends DBSearch
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : 'IN', 'NOT IN', 'Contains',' Begins with', 'Finishes with', ...
|
||||
* If no operator is specified then :
|
||||
* * for id field we will use "="
|
||||
* * for other fields we will call the corresponding {@link AttributeDefinition::GetSmartConditionExpression} method impl
|
||||
* to generate the expression
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -1228,7 +1232,7 @@ class DBObjectSearch extends DBSearch
|
||||
elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass()))
|
||||
{
|
||||
// Specialize $oRightFilter
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetClass());
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1623,7 +1623,7 @@ abstract class DBSearch
|
||||
$oSet = new DBObjectSet($this);
|
||||
if (MetaModel::IsStandaloneClass($sClass))
|
||||
{
|
||||
$oSet->OptimizeColumnLoad(array($this->GetClassAlias() => array('')));
|
||||
$oSet->OptimizeColumnLoad(array($this->GetClassAlias() => array()));
|
||||
$aIds = array($sClass => $oSet->GetColumnAsArray('id'));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -416,7 +416,11 @@ class DBUnionSearch extends DBSearch
|
||||
$aSearches = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
if (!$oSearch->IsAllDataAllowed()) {
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
} else {
|
||||
$aSearches[] = $oSearch;
|
||||
}
|
||||
}
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ class Dict
|
||||
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
|
||||
protected static $m_aData = array();
|
||||
protected static $m_sApplicationPrefix = null;
|
||||
/** @var \ApcService $m_oApcService */
|
||||
protected static $m_oApcService = null;
|
||||
|
||||
/**
|
||||
* @param $sLanguageCode
|
||||
@@ -145,15 +147,17 @@ class Dict
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
self::InitLangIfNeeded(self::GetUserLanguage());
|
||||
$sLangCode = self::GetUserLanguage();
|
||||
self::InitLangIfNeeded($sLangCode);
|
||||
|
||||
if (!array_key_exists(self::GetUserLanguage(), self::$m_aData))
|
||||
if (!array_key_exists($sLangCode, self::$m_aData))
|
||||
{
|
||||
IssueLog::Warning("Cannot find $sLangCode in dictionnaries. default labels displayed");
|
||||
// It may happen, when something happens before the dictionaries get loaded
|
||||
return $sStringCode;
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[self::GetUserLanguage()];
|
||||
if (array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
$aCurrentDictionary = self::$m_aData[$sLangCode];
|
||||
if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
}
|
||||
@@ -164,7 +168,7 @@ class Dict
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
|
||||
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
|
||||
if (array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
@@ -173,7 +177,7 @@ class Dict
|
||||
self::InitLangIfNeeded('EN US');
|
||||
|
||||
$aDefaultDictionary = self::$m_aData['EN US'];
|
||||
if (array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
@@ -232,7 +236,26 @@ class Dict
|
||||
{
|
||||
self::$m_aLanguages = $aLanguagesList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.7.6 N°4125
|
||||
* @return \ApcService
|
||||
*/
|
||||
public static function GetApcService() {
|
||||
if (self::$m_oApcService === null){
|
||||
self::$m_oApcService = new ApcService();
|
||||
}
|
||||
return self::$m_oApcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.6 N°4125
|
||||
* @param \ApcService $m_oApcService
|
||||
*/
|
||||
public static function SetApcService($oApcService) {
|
||||
self::$m_oApcService = $oApcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a language from the language dictionary, if not already loaded
|
||||
* @param string $sLangCode Language code
|
||||
@@ -241,20 +264,23 @@ class Dict
|
||||
public static function InitLangIfNeeded($sLangCode)
|
||||
{
|
||||
if (array_key_exists($sLangCode, self::$m_aData)) return true;
|
||||
|
||||
|
||||
$bResult = false;
|
||||
|
||||
if (function_exists('apc_fetch') && (self::$m_sApplicationPrefix !== null))
|
||||
|
||||
if (self::GetApcService()->function_exists('apc_fetch')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
//
|
||||
self::$m_aData[$sLangCode] = apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode);
|
||||
if (self::$m_aData[$sLangCode] === false)
|
||||
{
|
||||
self::$m_aData[$sLangCode] = self::GetApcService()->apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode);
|
||||
if (self::$m_aData[$sLangCode] === false) {
|
||||
unset(self::$m_aData[$sLangCode]);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (! is_array(self::$m_aData[$sLangCode])) {
|
||||
// N°4125: we dont fix dictionnary corrupted cache (on iTop side).
|
||||
// but we log an error in a dedicated channel to let itop administrator be aware of a potential APCu issue to fix.
|
||||
IssueLog::Error("APCu corrupted data (with $sLangCode dictionnary). APCu configuration and running version should be troubleshooted...", LogChannels::APC);
|
||||
$bResult = true;
|
||||
} else {
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
@@ -263,9 +289,10 @@ class Dict
|
||||
$sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php';
|
||||
require_once($sDictFile);
|
||||
|
||||
if (function_exists('apc_store') && (self::$m_sApplicationPrefix !== null))
|
||||
if (self::GetApcService()->function_exists('apc_store')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]);
|
||||
self::GetApcService()->apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]);
|
||||
}
|
||||
$bResult = true;
|
||||
}
|
||||
|
||||
@@ -1203,8 +1203,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
* @param float $xMax Right coordinate of the bounding box to display the graph
|
||||
* @param float $yMin Top coordinate of the bounding box to display the graph
|
||||
* @param float $yMax Bottom coordinate of the bounding box to display the graph
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°4985 $sComments param is no longer optional
|
||||
*/
|
||||
function RenderAsPDF(PDFPage $oPage, $sComments = '', $sContextKey, $xMin = -1, $xMax = -1, $yMin = -1, $yMax = -1)
|
||||
function RenderAsPDF(PDFPage $oPage, $sComments, $sContextKey, $xMin = -1, $xMax = -1, $yMin = -1, $yMax = -1)
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, false); // No need to develop the parameters
|
||||
$oPdf = $oPage->get_tcpdf();
|
||||
@@ -1431,83 +1433,25 @@ class DisplayableGraph extends SimpleGraph
|
||||
* @param int $iObjKey
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param bool $bLazyLoading since 2.7.7 3.0.1
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array())
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach($aExcludedObjects as $oObj)
|
||||
{
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass))
|
||||
{
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$sSearchToggle = Dict::S('UI:Search:Toggle');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oP->add(
|
||||
<<<EOF
|
||||
<div id="ds_flash" class="search_box">
|
||||
<form id="dh_flash" class="search_form_handler closed">
|
||||
<h2 class="sf_title"><span class="sft_long">$sSftShort</span><span class="sft_short">$sSftShort</span><span class="sft_toggler fas fa-caret-down pull-right" title="$sSearchToggle"></span></h2>
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").click( function() {
|
||||
$("#dh_flash").toggleClass('closed');
|
||||
});
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
EOF
|
||||
);
|
||||
$aSortedElements = array();
|
||||
foreach($aResults as $sClassIdx => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $oCurrObj)
|
||||
{
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$idx++;
|
||||
}
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></p>");
|
||||
$oP->add("</div></div></form>");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("</div>\n"); // class="not-printable"
|
||||
|
||||
$aAdditionalContexts = array();
|
||||
foreach($aContextDefs as $sKey => $aDefinition)
|
||||
{
|
||||
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
|
||||
}
|
||||
|
||||
$sDirection = utils::ReadParam('d', 'horizontal');
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), $bLazyLoading = false)
|
||||
{
|
||||
list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
|
||||
try
|
||||
{
|
||||
$this->InitFromGraphviz();
|
||||
$sExportAsPdfURL = '';
|
||||
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$oAppcontext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
|
||||
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
@@ -1586,7 +1530,14 @@ EOF
|
||||
// Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple
|
||||
unset($aParams['export_as_attachment']);
|
||||
}
|
||||
$oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
if ($oP->IsPrintableVersion() || !$bLazyLoading) {
|
||||
$oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
} else {
|
||||
$oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
|
||||
$oP->add_ready_script("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
@@ -1618,5 +1569,86 @@ EOF
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param array $aExcludedObjects
|
||||
* @param \WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 2.7.7 & 3.0.1
|
||||
*/
|
||||
protected function DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading)
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach ($aExcludedObjects as $oObj) {
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$sSearchToggle = Dict::S('UI:Search:Toggle');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oP->add(
|
||||
<<<EOF
|
||||
<div id="ds_flash" class="search_box">
|
||||
<form id="dh_flash" class="search_form_handler">
|
||||
<h2 class="sf_title"><span class="sft_long">$sSftShort</span><span class="sft_short">$sSftShort</span><span class="sft_toggler fas fa-caret-down pull-right" title="$sSearchToggle"></span></h2>
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").click( function() {
|
||||
$("#dh_flash").toggleClass('closed');
|
||||
});
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
EOF
|
||||
);
|
||||
if ($bLazyLoading) {
|
||||
$oP->add_ready_script("$('#ReloadMovieBtn').button('enable');");
|
||||
} else {
|
||||
$oP->add_ready_script("$('#dh_flash').addClass('closed');");
|
||||
}
|
||||
$aSortedElements = array();
|
||||
foreach ($aResults as $sClassIdx => $aObjects) {
|
||||
foreach ($aObjects as $oCurrObj) {
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach ($aSortedElements as $sSubClass => $sClassName) {
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$idx++;
|
||||
}
|
||||
if ($bLazyLoading) {
|
||||
$sOnCLick = "Load(); $('#ReloadMovieBtn').attr('onclick','DoReload()');$('#ReloadMovieBtn').html('".Dict::S('UI:Button:Refresh')."');";
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"$sOnCLick\">".Dict::S('Relation:impacts/LoadData')."</button></p>");
|
||||
} else {
|
||||
$sOnCLick = "DoReload()";
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></p>");
|
||||
}
|
||||
$oP->add("</div></div></form>");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("</div>\n"); // class="not-printable"
|
||||
|
||||
$aAdditionalContexts = array();
|
||||
foreach ($aContextDefs as $sKey => $aDefinition) {
|
||||
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
|
||||
}
|
||||
|
||||
return array($aExcludedByClass, $aAdditionalContexts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,38 +24,69 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Swift_Preferences::getInstance()->setCharset('UTF-8');
|
||||
use Combodo\iTop\Core\Email\EmailFactory;
|
||||
use Combodo\iTop\Core\Email\iEMail;
|
||||
|
||||
|
||||
define ('EMAIL_SEND_OK', 0);
|
||||
define ('EMAIL_SEND_PENDING', 1);
|
||||
define ('EMAIL_SEND_ERROR', 2);
|
||||
|
||||
class EMail
|
||||
class EMail implements iEMail
|
||||
{
|
||||
/**
|
||||
* @see self::LoadConfig()
|
||||
* @var Config
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3169 N°5102 Move attribute to children classes
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°4947 pull up the attribute back to the Email class as config init is done here
|
||||
*/
|
||||
protected static $m_oConfig = null;
|
||||
protected $oMailer;
|
||||
|
||||
// Serialization formats
|
||||
const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
|
||||
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
|
||||
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
|
||||
const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
|
||||
|
||||
protected static $m_oConfig = null;
|
||||
protected $m_aData; // For storing data to serialize
|
||||
|
||||
public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE)
|
||||
{
|
||||
if (is_null(self::$m_oConfig))
|
||||
{
|
||||
self::$m_oConfig = new Config($sConfigFile);
|
||||
}
|
||||
}
|
||||
|
||||
protected $m_oMessage;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_aData = array();
|
||||
$this->m_oMessage = Swift_Message::newInstance();
|
||||
$this->SetRecipientFrom(MetaModel::GetConfig()->Get('email_default_sender_address'), MetaModel::GetConfig()->Get('email_default_sender_label'));
|
||||
$this->oMailer = EmailFactory::GetMailer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@see m_oConfig} if current attribute is null
|
||||
*
|
||||
* @returns \Config the current {@see m_oConfig} value
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @uses utils::GetConfig()
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3169 N°5102 Move method to children classes
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°4947 Pull up to the parent class, and remove `$sConfigFile` param
|
||||
*/
|
||||
public function LoadConfig()
|
||||
{
|
||||
if (is_null(static::$m_oConfig)) {
|
||||
static::$m_oConfig = utils::GetConfig();
|
||||
}
|
||||
|
||||
return static::$m_oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°4947 Method creation, to factorize same code in children classes
|
||||
*/
|
||||
protected function InitRecipientFrom()
|
||||
{
|
||||
$oConfig = $this->LoadConfig();
|
||||
$this->SetRecipientFrom(
|
||||
$oConfig->Get('email_default_sender_address'),
|
||||
$oConfig->Get('email_default_sender_label')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,485 +97,96 @@ class EMail
|
||||
*/
|
||||
public function SerializeV2()
|
||||
{
|
||||
return serialize($this->m_aData);
|
||||
return $this->oMailer->SerializeV2();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Custom de-serialization method
|
||||
*
|
||||
* @param string $sSerializedMessage The serialized representation of the message
|
||||
*
|
||||
* @return \Email
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
|
||||
*/
|
||||
static public function UnSerializeV2($sSerializedMessage)
|
||||
{
|
||||
$aData = unserialize($sSerializedMessage);
|
||||
$oMessage = new Email();
|
||||
|
||||
if (array_key_exists('body', $aData))
|
||||
{
|
||||
$oMessage->SetBody($aData['body']['body'], $aData['body']['mimeType']);
|
||||
}
|
||||
if (array_key_exists('message_id', $aData))
|
||||
{
|
||||
$oMessage->SetMessageId($aData['message_id']);
|
||||
}
|
||||
if (array_key_exists('bcc', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientBCC($aData['bcc']);
|
||||
}
|
||||
if (array_key_exists('cc', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientCC($aData['cc']);
|
||||
}
|
||||
if (array_key_exists('from', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientFrom($aData['from']['address'], $aData['from']['label']);
|
||||
}
|
||||
if (array_key_exists('reply_to', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientReplyTo($aData['reply_to']);
|
||||
}
|
||||
if (array_key_exists('to', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientTO($aData['to']);
|
||||
}
|
||||
if (array_key_exists('subject', $aData))
|
||||
{
|
||||
$oMessage->SetSubject($aData['subject']);
|
||||
}
|
||||
|
||||
|
||||
if (array_key_exists('headers', $aData))
|
||||
{
|
||||
foreach($aData['headers'] as $sKey => $sValue)
|
||||
{
|
||||
$oMessage->AddToHeader($sKey, $sValue);
|
||||
}
|
||||
}
|
||||
if (array_key_exists('parts', $aData))
|
||||
{
|
||||
foreach($aData['parts'] as $aPart)
|
||||
{
|
||||
$oMessage->AddPart($aPart['text'], $aPart['mimeType']);
|
||||
}
|
||||
}
|
||||
if (array_key_exists('attachments', $aData))
|
||||
{
|
||||
foreach($aData['attachments'] as $aAttachment)
|
||||
{
|
||||
$oMessage->AddAttachment(base64_decode($aAttachment['data']), $aAttachment['filename'], $aAttachment['mimeType']);
|
||||
}
|
||||
}
|
||||
return $oMessage;
|
||||
}
|
||||
|
||||
protected function SendAsynchronous(&$aIssues, $oLog = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
AsyncSendEmail::AddToQueue($this, $oLog);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aIssues = array($e->GetMessage());
|
||||
return EMAIL_SEND_ERROR;
|
||||
}
|
||||
$aIssues = array();
|
||||
return EMAIL_SEND_PENDING;
|
||||
}
|
||||
|
||||
protected function SendSynchronous(&$aIssues, $oLog = null)
|
||||
{
|
||||
// If the body of the message is in HTML, embed all images based on attachments
|
||||
$this->EmbedInlineImages();
|
||||
|
||||
$this->LoadConfig();
|
||||
|
||||
$sTransport = self::$m_oConfig->Get('email_transport');
|
||||
switch ($sTransport)
|
||||
{
|
||||
case 'SMTP':
|
||||
$sHost = self::$m_oConfig->Get('email_transport_smtp.host');
|
||||
$sPort = self::$m_oConfig->Get('email_transport_smtp.port');
|
||||
$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption');
|
||||
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
|
||||
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');
|
||||
|
||||
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
|
||||
if (strlen($sUserName) > 0)
|
||||
{
|
||||
$oTransport->setUsername($sUserName);
|
||||
$oTransport->setPassword($sPassword);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Null':
|
||||
$oTransport = Swift_NullTransport::newInstance();
|
||||
break;
|
||||
|
||||
case 'LogFile':
|
||||
$oTransport = Swift_LogFileTransport::newInstance();
|
||||
$oTransport->setLogFile(APPROOT.'log/mail.log');
|
||||
break;
|
||||
|
||||
case 'PHPMail':
|
||||
default:
|
||||
$oTransport = Swift_MailTransport::newInstance();
|
||||
}
|
||||
|
||||
$oMailer = Swift_Mailer::newInstance($oTransport);
|
||||
|
||||
$aFailedRecipients = array();
|
||||
$this->m_oMessage->setMaxLineLength(0);
|
||||
$oKPI = new ExecutionKPI();
|
||||
try
|
||||
{
|
||||
$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
|
||||
if ($iSent === 0)
|
||||
{
|
||||
// Beware: it seems that $aFailedRecipients sometimes contains the recipients that actually received the message !!!
|
||||
IssueLog::Warning('Email sending failed: Some recipients were invalid, aFailedRecipients contains: '.implode(', ', $aFailedRecipients));
|
||||
$aIssues = array('Some recipients were invalid.');
|
||||
$oKPI->ComputeStats('Email Sent', 'Error received');
|
||||
return EMAIL_SEND_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aIssues = array();
|
||||
$oKPI->ComputeStats('Email Sent', 'Succeded');
|
||||
return EMAIL_SEND_OK;
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oKPI->ComputeStats('Email Sent', 'Error received');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reprocess the body of the message (if it is an HTML message)
|
||||
* to replace the URL of images based on attachments by a link
|
||||
* to an embedded image (i.e. cid:....)
|
||||
*/
|
||||
protected function EmbedInlineImages()
|
||||
{
|
||||
if ($this->m_aData['body']['mimeType'] == 'text/html')
|
||||
{
|
||||
$oDOMDoc = new DOMDocument();
|
||||
$oDOMDoc->preserveWhitespace = true;
|
||||
@$oDOMDoc->loadHTML('<?xml encoding="UTF-8"?>'.$this->m_aData['body']['body']); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
$oXPath = new DOMXPath($oDOMDoc);
|
||||
$sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']';
|
||||
$oImagesList = $oXPath->query($sXPath);
|
||||
|
||||
if ($oImagesList->length != 0)
|
||||
{
|
||||
foreach($oImagesList as $oImg)
|
||||
{
|
||||
$iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID);
|
||||
$oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */);
|
||||
if ($oAttachment)
|
||||
{
|
||||
$sImageSecret = $oImg->getAttribute('data-img-secret');
|
||||
$sAttachmentSecret = $oAttachment->Get('secret');
|
||||
if ($sImageSecret !== $sAttachmentSecret)
|
||||
{
|
||||
// @see N°1921
|
||||
// If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret
|
||||
continue;
|
||||
}
|
||||
|
||||
$oDoc = $oAttachment->Get('contents');
|
||||
$oSwiftImage = new Swift_Image($oDoc->GetData(), $oDoc->GetFileName(), $oDoc->GetMimeType());
|
||||
$sCid = $this->m_oMessage->embed($oSwiftImage);
|
||||
$oImg->setAttribute('src', $sCid);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtmlBody = $oDOMDoc->saveHTML();
|
||||
$this->m_oMessage->setBody($sHtmlBody, 'text/html', 'UTF-8');
|
||||
}
|
||||
return EmailFactory::GetMailer()::UnSerializeV2($sSerializedMessage);
|
||||
}
|
||||
|
||||
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
|
||||
{
|
||||
//select a default sender if none is provided.
|
||||
if(empty($this->m_aData['from']['address']) && !empty($this->m_aData['to'])){
|
||||
$this->SetRecipientFrom($this->m_aData['to']);
|
||||
}
|
||||
|
||||
if ($bForceSynchronous)
|
||||
{
|
||||
return $this->SendSynchronous($aIssues, $oLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bConfigASYNC = MetaModel::GetConfig()->Get('email_asynchronous');
|
||||
if ($bConfigASYNC)
|
||||
{
|
||||
return $this->SendAsynchronous($aIssues, $oLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->SendSynchronous($aIssues, $oLog);
|
||||
}
|
||||
}
|
||||
return $this->oMailer->Send($aIssues, $bForceSynchronous, $oLog);
|
||||
}
|
||||
|
||||
public function AddToHeader($sKey, $sValue)
|
||||
{
|
||||
if (!array_key_exists('headers', $this->m_aData))
|
||||
{
|
||||
$this->m_aData['headers'] = array();
|
||||
}
|
||||
$this->m_aData['headers'][$sKey] = $sValue;
|
||||
|
||||
if (strlen($sValue) > 0)
|
||||
{
|
||||
$oHeaders = $this->m_oMessage->getHeaders();
|
||||
switch(strtolower($sKey))
|
||||
{
|
||||
case 'return-path':
|
||||
$this->m_oMessage->setReturnPath($sValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oHeaders->addTextHeader($sKey, $sValue);
|
||||
}
|
||||
}
|
||||
$this->oMailer->AddToHeader($sKey, $sValue);
|
||||
}
|
||||
|
||||
public function SetMessageId($sId)
|
||||
{
|
||||
$this->m_aData['message_id'] = $sId;
|
||||
|
||||
// Note: Swift will add the angle brackets for you
|
||||
// so let's remove the angle brackets if present, for historical reasons
|
||||
$sId = str_replace(array('<', '>'), '', $sId);
|
||||
|
||||
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
|
||||
$oMsgId->SetId($sId);
|
||||
$this->oMailer->SetMessageId($sId);
|
||||
}
|
||||
|
||||
public function SetReferences($sReferences)
|
||||
{
|
||||
$this->AddToHeader('References', $sReferences);
|
||||
$this->oMailer->SetReferences($sReferences);
|
||||
}
|
||||
|
||||
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
|
||||
{
|
||||
if (($sMimeType === 'text/html') && ($sCustomStyles !== null))
|
||||
{
|
||||
$emogrifier = new \Pelago\Emogrifier($sBody, $sCustomStyles);
|
||||
$sBody = $emogrifier->emogrify(); // Adds html/body tags if not already present
|
||||
}
|
||||
$this->m_aData['body'] = array('body' => $sBody, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->setBody($sBody, $sMimeType);
|
||||
$this->oMailer->SetBody($sBody, $sMimeType, $sCustomStyles);
|
||||
}
|
||||
|
||||
public function AddPart($sText, $sMimeType = 'text/html')
|
||||
{
|
||||
if (!array_key_exists('parts', $this->m_aData))
|
||||
{
|
||||
$this->m_aData['parts'] = array();
|
||||
}
|
||||
$this->m_aData['parts'][] = array('text' => $sText, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->addPart($sText, $sMimeType);
|
||||
$this->oMailer->AddPart($sText, $sMimeType);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
if (!array_key_exists('attachments', $this->m_aData))
|
||||
{
|
||||
$this->m_aData['attachments'] = array();
|
||||
}
|
||||
$this->m_aData['attachments'][] = array('data' => base64_encode($data), 'filename' => $sFileName, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
|
||||
$this->oMailer->AddAttachment($data, $sFileName, $sMimeType);
|
||||
}
|
||||
|
||||
public function SetSubject($sSubject)
|
||||
{
|
||||
$this->m_aData['subject'] = $sSubject;
|
||||
$this->m_oMessage->setSubject($sSubject);
|
||||
$this->oMailer->SetSubject($sSubject);
|
||||
}
|
||||
|
||||
public function GetSubject()
|
||||
{
|
||||
return $this->m_oMessage->getSubject();
|
||||
return $this->oMailer->GetSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to transform and sanitize addresses
|
||||
* - get rid of empty addresses
|
||||
*/
|
||||
protected function AddressStringToArray($sAddressCSVList)
|
||||
{
|
||||
$aAddresses = array();
|
||||
foreach(explode(',', $sAddressCSVList) as $sAddress)
|
||||
{
|
||||
$sAddress = trim($sAddress);
|
||||
if (strlen($sAddress) > 0)
|
||||
{
|
||||
$aAddresses[] = $sAddress;
|
||||
}
|
||||
}
|
||||
return $aAddresses;
|
||||
}
|
||||
|
||||
public function SetRecipientTO($sAddress)
|
||||
{
|
||||
$this->m_aData['to'] = $sAddress;
|
||||
if (!empty($sAddress))
|
||||
{
|
||||
$aAddresses = $this->AddressStringToArray($sAddress);
|
||||
$this->m_oMessage->setTo($aAddresses);
|
||||
}
|
||||
$this->oMailer->SetRecipientTO($sAddress);
|
||||
}
|
||||
|
||||
public function GetRecipientTO($bAsString = false)
|
||||
{
|
||||
$aRes = $this->m_oMessage->getTo();
|
||||
if ($aRes === null)
|
||||
{
|
||||
// There is no "To" header field
|
||||
$aRes = array();
|
||||
}
|
||||
if ($bAsString)
|
||||
{
|
||||
$aStrings = array();
|
||||
foreach ($aRes as $sEmail => $sName)
|
||||
{
|
||||
if (is_null($sName))
|
||||
{
|
||||
$aStrings[] = $sEmail;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sName = str_replace(array('<', '>'), '', $sName);
|
||||
$aStrings[] = "$sName <$sEmail>";
|
||||
}
|
||||
}
|
||||
return implode(', ', $aStrings);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $aRes;
|
||||
}
|
||||
return $this->oMailer->GetRecipientTO($bAsString);
|
||||
}
|
||||
|
||||
public function SetRecipientCC($sAddress)
|
||||
{
|
||||
$this->m_aData['cc'] = $sAddress;
|
||||
if (!empty($sAddress))
|
||||
{
|
||||
$aAddresses = $this->AddressStringToArray($sAddress);
|
||||
$this->m_oMessage->setCc($aAddresses);
|
||||
}
|
||||
$this->oMailer->SetRecipientCC($sAddress);
|
||||
}
|
||||
|
||||
public function SetRecipientBCC($sAddress)
|
||||
{
|
||||
$this->m_aData['bcc'] = $sAddress;
|
||||
if (!empty($sAddress))
|
||||
{
|
||||
$aAddresses = $this->AddressStringToArray($sAddress);
|
||||
$this->m_oMessage->setBcc($aAddresses);
|
||||
}
|
||||
$this->oMailer->SetRecipientBCC($sAddress);
|
||||
}
|
||||
|
||||
public function SetRecipientFrom($sAddress, $sLabel = '')
|
||||
{
|
||||
$this->m_aData['from'] = array('address' => $sAddress, 'label' => $sLabel);
|
||||
if ($sLabel != '')
|
||||
{
|
||||
$this->m_oMessage->setFrom(array($sAddress => $sLabel));
|
||||
}
|
||||
else if (!empty($sAddress))
|
||||
{
|
||||
$this->m_oMessage->setFrom($sAddress);
|
||||
}
|
||||
$this->oMailer->SetRecipientFrom($sAddress, $sLabel);
|
||||
}
|
||||
|
||||
public function SetRecipientReplyTo($sAddress)
|
||||
{
|
||||
$this->m_aData['reply_to'] = $sAddress;
|
||||
if (!empty($sAddress))
|
||||
{
|
||||
$this->m_oMessage->setReplyTo($sAddress);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Extension to SwiftMailer: "debug" transport that pretends messages have been sent,
|
||||
* but just log them to a file.
|
||||
*
|
||||
* @package Swift
|
||||
* @author Denis Flaven
|
||||
*/
|
||||
class Swift_Transport_LogFileTransport extends Swift_Transport_NullTransport
|
||||
{
|
||||
protected $sLogFile;
|
||||
|
||||
/**
|
||||
* Sends the given message.
|
||||
*
|
||||
* @param Swift_Mime_Message $message
|
||||
* @param string[] $failedRecipients An array of failures by-reference
|
||||
*
|
||||
* @return int The number of sent emails
|
||||
*/
|
||||
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
|
||||
{
|
||||
$hFile = @fopen($this->sLogFile, 'a');
|
||||
if ($hFile)
|
||||
{
|
||||
$sTxt = "================== ".date('Y-m-d H:i:s')." ==================\n";
|
||||
$sTxt .= $message->toString()."\n";
|
||||
|
||||
@fwrite($hFile, $sTxt);
|
||||
@fclose($hFile);
|
||||
}
|
||||
|
||||
return parent::send($message, $failedRecipients);
|
||||
}
|
||||
|
||||
public function setLogFile($sFilename)
|
||||
{
|
||||
$this->sLogFile = $sFilename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretends messages have been sent, but just log them to a file.
|
||||
*
|
||||
* @package Swift
|
||||
* @author Denis Flaven
|
||||
*/
|
||||
class Swift_LogFileTransport extends Swift_Transport_LogFileTransport
|
||||
{
|
||||
/**
|
||||
* Create a new LogFileTransport.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
call_user_func_array(
|
||||
array($this, 'Swift_Transport_LogFileTransport::__construct'),
|
||||
Swift_DependencyContainer::getInstance()
|
||||
->createDependenciesFor('transport.null')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LogFileTransport instance.
|
||||
*
|
||||
* @return Swift_LogFileTransport
|
||||
*/
|
||||
public static function newInstance()
|
||||
{
|
||||
return new self();
|
||||
$this->oMailer->SetRecipientReplyTo($sAddress);
|
||||
}
|
||||
}
|
||||
@@ -34,43 +34,51 @@ abstract class HTMLSanitizer
|
||||
|
||||
/**
|
||||
* Sanitize an HTML string with the configured sanitizer, falling back to HTMLDOMSanitizer in case of Exception or invalid configuration
|
||||
*
|
||||
* @param string $sHTML
|
||||
* @param string $sConfigKey
|
||||
*
|
||||
* @return string
|
||||
* @noinspection SelfClassReferencingInspection
|
||||
*/
|
||||
public static function Sanitize($sHTML)
|
||||
public static function Sanitize($sHTML, $sConfigKey = 'html_sanitizer')
|
||||
{
|
||||
$sSanitizerClass = MetaModel::GetConfig()->Get('html_sanitizer');
|
||||
if(!class_exists($sSanitizerClass))
|
||||
{
|
||||
IssueLog::Warning('The configured "html_sanitizer" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = MetaModel::GetConfig()->Get($sConfigKey);
|
||||
if (!class_exists($sSanitizerClass)) {
|
||||
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
} else if (false === is_subclass_of($sSanitizerClass, HTMLSanitizer::class)) {
|
||||
if ($sConfigKey === 'html_sanitizer') {
|
||||
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
}
|
||||
if ($sConfigKey === 'svg_sanitizer') {
|
||||
IssueLog::Error('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.' ! Won\'t sanitize string.');
|
||||
|
||||
return $sHTML;
|
||||
}
|
||||
}
|
||||
else if(!is_subclass_of($sSanitizerClass, 'HTMLSanitizer'))
|
||||
{
|
||||
IssueLog::Warning('The configured "html_sanitizer" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
try {
|
||||
$oSanitizer = new $sSanitizerClass();
|
||||
$sCleanHTML = $oSanitizer->DoSanitize($sHTML);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
if($sSanitizerClass != 'HTMLDOMSanitizer')
|
||||
{
|
||||
IssueLog::Warning('Failed to sanitize an HTML string with "'.$sSanitizerClass.'". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Warning('Will try to sanitize with HTMLDOMSanitizer.');
|
||||
// try again with the HTMLDOMSanitizer
|
||||
$oSanitizer = new HTMLDOMSanitizer();
|
||||
$sCleanHTML = $oSanitizer->DoSanitize($sHTML);
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Error('Failed to sanitize an HTML string with "HTMLDOMSanitizer". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Error('The HTML will NOT be sanitized.');
|
||||
$sCleanHTML = $sHTML;
|
||||
catch(Exception $e) {
|
||||
if ($sConfigKey === 'html_sanitizer') {
|
||||
if ($sSanitizerClass !== HTMLDOMSanitizer::class) {
|
||||
IssueLog::Warning('Failed to sanitize an HTML string with "'.$sSanitizerClass.'". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Warning('Will try to sanitize with HTMLDOMSanitizer.');
|
||||
// try again with the HTMLDOMSanitizer
|
||||
$oSanitizer = new HTMLDOMSanitizer();
|
||||
$sCleanHTML = $oSanitizer->DoSanitize($sHTML);
|
||||
} else {
|
||||
IssueLog::Error('Failed to sanitize an HTML string with "HTMLDOMSanitizer". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Error('The HTML will NOT be sanitized.');
|
||||
$sCleanHTML = $sHTML;
|
||||
}
|
||||
} else {
|
||||
IssueLog::Error('Failed to sanitize string with "'.$sSanitizerClass.'", will return original value ! Exception: '.$e->getMessage());
|
||||
$sCleanHTML = $sHTML;
|
||||
}
|
||||
}
|
||||
return $sCleanHTML;
|
||||
@@ -97,67 +105,179 @@ class HTMLNullSanitizer extends HTMLSanitizer
|
||||
{
|
||||
return $sHTML;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A standard-compliant HTMLSanitizer based on the HTMLPurifier library by Edward Z. Yang
|
||||
* Complete but quite slow
|
||||
* http://htmlpurifier.org
|
||||
* Common implementation for sanitizer using DOM parsing
|
||||
*/
|
||||
/*
|
||||
class HTMLPurifierSanitizer extends HTMLSanitizer
|
||||
abstract class DOMSanitizer extends HTMLSanitizer
|
||||
{
|
||||
protected static $oPurifier = null;
|
||||
|
||||
public function __construct()
|
||||
/** @var DOMDocument */
|
||||
protected $oDoc;
|
||||
/**
|
||||
* @var string Class to use for InlineImage static method calls
|
||||
* @used-by \Combodo\iTop\Test\UnitTest\Core\Sanitizer\HTMLDOMSanitizerTest::testDoSanitizeCallInlineImageProcessImageTag
|
||||
*/
|
||||
protected $sInlineImageClassName;
|
||||
|
||||
public function __construct($sInlineImageClassName = InlineImage::class)
|
||||
{
|
||||
if (self::$oPurifier == null)
|
||||
{
|
||||
$sLibPath = APPROOT.'lib/htmlpurifier/HTMLPurifier.auto.php';
|
||||
if (!file_exists($sLibPath))
|
||||
{
|
||||
throw new Exception("Missing library '$sLibPath', cannot use HTMLPurifierSanitizer.");
|
||||
}
|
||||
require_once($sLibPath);
|
||||
|
||||
$oPurifierConfig = HTMLPurifier_Config::createDefault();
|
||||
$oPurifierConfig->set('Core.Encoding', 'UTF-8'); // defaults to 'UTF-8'
|
||||
$oPurifierConfig->set('HTML.Doctype', 'XHTML 1.0 Strict'); // defaults to 'XHTML 1.0 Transitional'
|
||||
$oPurifierConfig->set('URI.AllowedSchemes', array (
|
||||
'http' => true,
|
||||
'https' => true,
|
||||
'data' => true, // This one is not present by default
|
||||
));
|
||||
$sPurifierCache = APPROOT.'data/HTMLPurifier';
|
||||
if (!is_dir($sPurifierCache))
|
||||
{
|
||||
mkdir($sPurifierCache);
|
||||
}
|
||||
if (!is_dir($sPurifierCache))
|
||||
{
|
||||
throw new Exception("Could not create the cache directory '$sPurifierCache'");
|
||||
}
|
||||
$oPurifierConfig->set('Cache.SerializerPath', $sPurifierCache); // no trailing slash
|
||||
self::$oPurifier = new HTMLPurifier($oPurifierConfig);
|
||||
}
|
||||
parent::__construct();
|
||||
|
||||
$this->sInlineImageClassName = $sInlineImageClassName;
|
||||
}
|
||||
|
||||
|
||||
abstract public function GetTagsWhiteList();
|
||||
|
||||
abstract public function GetTagsBlackList();
|
||||
|
||||
abstract public function GetAttrsWhiteList();
|
||||
|
||||
abstract public function GetAttrsBlackList();
|
||||
|
||||
abstract public function GetStylesWhiteList();
|
||||
|
||||
public function DoSanitize($sHTML)
|
||||
{
|
||||
$sCleanHtml = self::$oPurifier->purify($sHTML);
|
||||
return $sCleanHtml;
|
||||
$this->oDoc = new DOMDocument();
|
||||
$this->oDoc->preserveWhitespace = true;
|
||||
|
||||
// MS outlook implements empty lines by the mean of <p><o:p></o:p></p>
|
||||
// We have to transform that into <p><br></p> (which is how Thunderbird implements empty lines)
|
||||
// Unfortunately, DOMDocument::loadHTML does not take the tag namespaces into account (once loaded there is no way to know if the tag did have a namespace)
|
||||
// therefore we have to do the transformation upfront
|
||||
$sHTML = preg_replace('@<o:p>(\s| )*</o:p>@', '<br>', $sHTML);
|
||||
|
||||
$this->LoadDoc($sHTML);
|
||||
|
||||
$this->CleanNode($this->oDoc);
|
||||
|
||||
$sCleanHtml = $this->PrintDoc();
|
||||
|
||||
return $sCleanHtml;
|
||||
}
|
||||
|
||||
abstract public function LoadDoc($sHTML);
|
||||
|
||||
/**
|
||||
* @return string cleaned source
|
||||
* @uses \DOMSanitizer::oDoc
|
||||
*/
|
||||
abstract public function PrintDoc();
|
||||
|
||||
protected function CleanNode(DOMNode $oElement)
|
||||
{
|
||||
$aAttrToRemove = array();
|
||||
// Gather the attributes to remove
|
||||
if ($oElement->hasAttributes()) {
|
||||
foreach ($oElement->attributes as $oAttr) {
|
||||
$sAttr = strtolower($oAttr->name);
|
||||
if ((false === empty($this->GetAttrsBlackList()))
|
||||
&& (in_array($sAttr, $this->GetAttrsBlackList(), true))) {
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
} else if ((false === empty($this->GetTagsWhiteList()))
|
||||
&& (false === in_array($sAttr, $this->GetTagsWhiteList()[strtolower($oElement->tagName)]))) {
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
} else if (!$this->IsValidAttributeContent($sAttr, $oAttr->value)) {
|
||||
// Invalid content
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
} else if ($sAttr == 'style') {
|
||||
// Special processing for style tags
|
||||
$sCleanStyle = $this->CleanStyle($oAttr->value);
|
||||
if ($sCleanStyle == '') {
|
||||
// Invalid content
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
} else {
|
||||
$oElement->setAttribute($oAttr->name, $sCleanStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now remove them
|
||||
foreach($aAttrToRemove as $sName)
|
||||
{
|
||||
$oElement->removeAttribute($sName);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oElement->hasChildNodes())
|
||||
{
|
||||
$aChildElementsToRemove = array();
|
||||
// Gather the child noes to remove
|
||||
foreach($oElement->childNodes as $oNode) {
|
||||
if ($oNode instanceof DOMElement) {
|
||||
$sNodeTagName = strtolower($oNode->tagName);
|
||||
}
|
||||
if (($oNode instanceof DOMElement)
|
||||
&& (false === empty($this->GetTagsBlackList()))
|
||||
&& (in_array($sNodeTagName, $this->GetTagsBlackList(), true))) {
|
||||
$aChildElementsToRemove[] = $oNode;
|
||||
} else if (($oNode instanceof DOMElement)
|
||||
&& (false === empty($this->GetTagsWhiteList()))
|
||||
&& (false === array_key_exists($sNodeTagName, $this->GetTagsWhiteList()))) {
|
||||
$aChildElementsToRemove[] = $oNode;
|
||||
} else if ($oNode instanceof DOMComment) {
|
||||
$aChildElementsToRemove[] = $oNode;
|
||||
} else {
|
||||
// Recurse
|
||||
$this->CleanNode($oNode);
|
||||
if (($oNode instanceof DOMElement) && (strtolower($oNode->tagName) == 'img')) {
|
||||
$this->sInlineImageClassName::ProcessImageTag($oNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now remove them
|
||||
foreach($aChildElementsToRemove as $oDomElement)
|
||||
{
|
||||
$oElement->removeChild($oDomElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function IsValidAttributeContent($sAttributeName, $sValue)
|
||||
{
|
||||
if ((false === empty($this->GetAttrsBlackList()))
|
||||
&& (in_array($sAttributeName, $this->GetAttrsBlackList(), true))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array_key_exists($sAttributeName, $this->GetAttrsWhiteList())) {
|
||||
return preg_match($this->GetAttrsWhiteList()[$sAttributeName], $sValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function CleanStyle($sStyle)
|
||||
{
|
||||
if (empty($this->GetStylesWhiteList())) {
|
||||
return $sStyle;
|
||||
}
|
||||
|
||||
$aAllowedStyles = array();
|
||||
$aItems = explode(';', $sStyle);
|
||||
{
|
||||
foreach ($aItems as $sItem) {
|
||||
$aElements = explode(':', trim($sItem));
|
||||
if (in_array(trim(strtolower($aElements[0])), $this->GetStylesWhiteList())) {
|
||||
$aAllowedStyles[] = trim($sItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode(';', $aAllowedStyles);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
|
||||
class HTMLDOMSanitizer extends DOMSanitizer
|
||||
{
|
||||
protected $oDoc;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
|
||||
* @var array
|
||||
*/
|
||||
protected static $aTagsWhiteList = array(
|
||||
'html' => array(),
|
||||
@@ -214,8 +334,8 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
|
||||
* @var array
|
||||
*/
|
||||
protected static $aStylesWhiteList = array(
|
||||
'background-color',
|
||||
@@ -239,164 +359,200 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
'white-space',
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
public function __construct($sInlineImageClassName = InlineImage::class)
|
||||
{
|
||||
parent::__construct();
|
||||
parent::__construct($sInlineImageClassName);
|
||||
|
||||
// Building href validation pattern from url and email validation patterns as the patterns are not used the same way in HTML content than in standard attributes value.
|
||||
// eg. "foo@bar.com" vs "mailto:foo@bar.com?subject=Title&body=Hello%20world"
|
||||
if (!array_key_exists('href', self::$aAttrsWhiteList))
|
||||
{
|
||||
if (!array_key_exists('href', self::$aAttrsWhiteList)) {
|
||||
// Regular urls
|
||||
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
|
||||
|
||||
// Mailto urls
|
||||
$sMailtoPattern = '(mailto:(' . utils::GetConfig()->Get('email_validation_pattern') . ')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
|
||||
$sMailtoPattern = '(mailto:('.utils::GetConfig()->Get('email_validation_pattern').')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
|
||||
|
||||
// Notification placeholders
|
||||
// eg. $this->caller_id$, $this->hyperlink()$, $this->hyperlink(portal)$, $APP_URL$, $MODULES_URL$, ...
|
||||
// Note: Authorize both $xxx$ and %24xxx%24 as the latter one is encoded when used in HTML attributes (eg. a[href])
|
||||
$sPlaceholderPattern = '(\$|%24)[\w-]*(->[\w]*(\([\w-]*?\))?)?(\$|%24)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern . '|' . $sPlaceholderPattern;
|
||||
$sPattern = $sUrlPattern.'|'.$sMailtoPattern.'|'.$sPlaceholderPattern;
|
||||
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
|
||||
self::$aAttrsWhiteList['href'] = $sPattern;
|
||||
}
|
||||
}
|
||||
|
||||
public function DoSanitize($sHTML)
|
||||
public function GetTagsWhiteList()
|
||||
{
|
||||
$this->oDoc = new DOMDocument();
|
||||
$this->oDoc->preserveWhitespace = true;
|
||||
return static::$aTagsWhiteList;
|
||||
}
|
||||
|
||||
// MS outlook implements empty lines by the mean of <p><o:p></o:p></p>
|
||||
// We have to transform that into <p><br></p> (which is how Thunderbird implements empty lines)
|
||||
// Unfortunately, DOMDocument::loadHTML does not take the tag namespaces into account (once loaded there is no way to know if the tag did have a namespace)
|
||||
// therefore we have to do the transformation upfront
|
||||
$sHTML = preg_replace('@<o:p>(\s| )*</o:p>@', '<br>', $sHTML);
|
||||
// Replace badly encoded non breaking space
|
||||
$sHTML = preg_replace('~\xc2\xa0~', ' ', $sHTML);
|
||||
public function GetTagsBlackList()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function GetAttrsWhiteList()
|
||||
{
|
||||
return static::$aAttrsWhiteList;
|
||||
}
|
||||
|
||||
public function GetAttrsBlackList()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function GetStylesWhiteList()
|
||||
{
|
||||
return static::$aStylesWhiteList;
|
||||
}
|
||||
|
||||
public function LoadDoc($sHTML)
|
||||
{
|
||||
@$this->oDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sHTML); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
$this->CleanNode($this->oDoc);
|
||||
|
||||
$this->oDoc->preserveWhitespace = true;
|
||||
}
|
||||
|
||||
public function PrintDoc()
|
||||
{
|
||||
$oXPath = new DOMXPath($this->oDoc);
|
||||
$sXPath = "//body";
|
||||
$oNodesList = $oXPath->query($sXPath);
|
||||
|
||||
if ($oNodesList->length == 0)
|
||||
{
|
||||
|
||||
if ($oNodesList->length == 0) {
|
||||
// No body, save the whole document
|
||||
$sCleanHtml = $this->oDoc->saveHTML();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Export only the content of the body tag
|
||||
$sCleanHtml = $this->oDoc->saveHTML($oNodesList->item(0));
|
||||
// remove the body tag itself
|
||||
$sCleanHtml = str_replace( array('<body>', '</body>'), '', $sCleanHtml);
|
||||
$sCleanHtml = str_replace(array('<body>', '</body>'), '', $sCleanHtml);
|
||||
}
|
||||
|
||||
|
||||
return $sCleanHtml;
|
||||
}
|
||||
|
||||
protected function CleanNode(DOMNode $oElement)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4360
|
||||
*/
|
||||
class SVGDOMSanitizer extends DOMSanitizer
|
||||
{
|
||||
public function GetTagsWhiteList()
|
||||
{
|
||||
$aAttrToRemove = array();
|
||||
// Gather the attributes to remove
|
||||
if ($oElement->hasAttributes())
|
||||
{
|
||||
foreach($oElement->attributes as $oAttr)
|
||||
{
|
||||
$sAttr = strtolower($oAttr->name);
|
||||
if (!in_array($sAttr, self::$aTagsWhiteList[strtolower($oElement->tagName)]))
|
||||
{
|
||||
// Forbidden (or unknown) attribute
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
}
|
||||
else if (!$this->IsValidAttributeContent($sAttr, $oAttr->value))
|
||||
{
|
||||
// Invalid content
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
}
|
||||
else if ($sAttr == 'style')
|
||||
{
|
||||
// Special processing for style tags
|
||||
$sCleanStyle = $this->CleanStyle($oAttr->value);
|
||||
if ($sCleanStyle == '')
|
||||
{
|
||||
// Invalid content
|
||||
$aAttrToRemove[] = $oAttr->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oElement->setAttribute($oAttr->name, $sCleanStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now remove them
|
||||
foreach($aAttrToRemove as $sName)
|
||||
{
|
||||
$oElement->removeAttribute($sName);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oElement->hasChildNodes())
|
||||
{
|
||||
$aChildElementsToRemove = array();
|
||||
// Gather the child noes to remove
|
||||
foreach($oElement->childNodes as $oNode)
|
||||
{
|
||||
if (($oNode instanceof DOMElement) && (!array_key_exists(strtolower($oNode->tagName), self::$aTagsWhiteList)))
|
||||
{
|
||||
$aChildElementsToRemove[] = $oNode;
|
||||
}
|
||||
else if ($oNode instanceof DOMComment)
|
||||
{
|
||||
$aChildElementsToRemove[] = $oNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recurse
|
||||
$this->CleanNode($oNode);
|
||||
if (($oNode instanceof DOMElement) && (strtolower($oNode->tagName) == 'img'))
|
||||
{
|
||||
InlineImage::ProcessImageTag($oNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now remove them
|
||||
foreach($aChildElementsToRemove as $oDomElement)
|
||||
{
|
||||
$oElement->removeChild($oDomElement);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function CleanStyle($sStyle)
|
||||
/**
|
||||
* @return string[]
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/script
|
||||
*/
|
||||
public function GetTagsBlackList()
|
||||
{
|
||||
$aAllowedStyles = array();
|
||||
$aItems = explode(';', $sStyle);
|
||||
{
|
||||
foreach($aItems as $sItem)
|
||||
{
|
||||
$aElements = explode(':', trim($sItem));
|
||||
if (in_array(trim(strtolower($aElements[0])), static::$aStylesWhiteList))
|
||||
{
|
||||
$aAllowedStyles[] = trim($sItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(';', $aAllowedStyles);
|
||||
return [
|
||||
'script',
|
||||
];
|
||||
}
|
||||
|
||||
protected function IsValidAttributeContent($sAttributeName, $sValue)
|
||||
|
||||
public function GetAttrsWhiteList()
|
||||
{
|
||||
if (array_key_exists($sAttributeName, self::$aAttrsWhiteList))
|
||||
{
|
||||
return preg_match(self::$aAttrsWhiteList[$sAttributeName], $sValue);
|
||||
}
|
||||
return true;
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Events#document_event_attributes
|
||||
*/
|
||||
public function GetAttrsBlackList()
|
||||
{
|
||||
return [
|
||||
'onbegin',
|
||||
'onbegin',
|
||||
'onrepeat',
|
||||
'onabort',
|
||||
'onerror',
|
||||
'onerror',
|
||||
'onscroll',
|
||||
'onunload',
|
||||
'oncopy',
|
||||
'oncut',
|
||||
'onpaste',
|
||||
'oncancel',
|
||||
'oncanplay',
|
||||
'oncanplaythrough',
|
||||
'onchange',
|
||||
'onclick',
|
||||
'onclose',
|
||||
'oncuechange',
|
||||
'ondblclick',
|
||||
'ondrag',
|
||||
'ondragend',
|
||||
'ondragenter',
|
||||
'ondragleave',
|
||||
'ondragover',
|
||||
'ondragstart',
|
||||
'ondrop',
|
||||
'ondurationchange',
|
||||
'onemptied',
|
||||
'onended',
|
||||
'onerror',
|
||||
'onfocus',
|
||||
'oninput',
|
||||
'oninvalid',
|
||||
'onkeydown',
|
||||
'onkeypress',
|
||||
'onkeyup',
|
||||
'onload',
|
||||
'onloadeddata',
|
||||
'onloadedmetadata',
|
||||
'onloadstart',
|
||||
'onmousedown',
|
||||
'onmouseenter',
|
||||
'onmouseleave',
|
||||
'onmousemove',
|
||||
'onmouseout',
|
||||
'onmouseover',
|
||||
'onmouseup',
|
||||
'onmousewheel',
|
||||
'onpause',
|
||||
'onplay',
|
||||
'onplaying',
|
||||
'onprogress',
|
||||
'onratechange',
|
||||
'onreset',
|
||||
'onresize',
|
||||
'onscroll',
|
||||
'onseeked',
|
||||
'onseeking',
|
||||
'onselect',
|
||||
'onshow',
|
||||
'onstalled',
|
||||
'onsubmit',
|
||||
'onsuspend',
|
||||
'ontimeupdate',
|
||||
'ontoggle',
|
||||
'onvolumechange',
|
||||
'onwaiting',
|
||||
'onactivate',
|
||||
'onfocusin',
|
||||
'onfocusout',
|
||||
];
|
||||
}
|
||||
|
||||
public function GetStylesWhiteList()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function LoadDoc($sHTML)
|
||||
{
|
||||
@$this->oDoc->loadXml($sHTML, LIBXML_NOBLANKS);
|
||||
}
|
||||
|
||||
public function PrintDoc()
|
||||
{
|
||||
return $this->oDoc->saveXML();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Parser;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
@@ -80,38 +82,49 @@ class iTopConfigParser
|
||||
* @param \PhpParser\Parser $oParser
|
||||
* @param $sConfig
|
||||
*
|
||||
* @return \Combodo\iTop\Config\Validator\ConfigNodesVisitor
|
||||
* @return void
|
||||
*/
|
||||
private function BrowseFile(\PhpParser\Parser $oParser, $sConfig)
|
||||
private function BrowseFile(Parser $oParser, $sConfig)
|
||||
{
|
||||
$prettyPrinter = new Standard();
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
$aNodes = $oParser->parse($sConfig);
|
||||
}
|
||||
catch (\Error $e)
|
||||
{
|
||||
catch (\Error $e) {
|
||||
$sMessage = Dict::Format('config-parse-error', $e->getMessage(), $e->getLine());
|
||||
$this->oException = new \Exception($sMessage, 0, $e);
|
||||
}
|
||||
|
||||
foreach ($aNodes as $oAssignation)
|
||||
{
|
||||
if (! $oAssignation instanceof Assign)
|
||||
{
|
||||
foreach ($aNodes as $sKey => $oNode) {
|
||||
// With PhpParser 3 we had an Assign node at root
|
||||
// In PhpParser 4 the root node is now an Expression
|
||||
|
||||
if (false === ($oNode instanceof \PhpParser\Node\Stmt\Expression)) {
|
||||
continue;
|
||||
}
|
||||
/** @var \PhpParser\Node\Stmt\Expression $oNode */
|
||||
|
||||
if (false === ($oNode->expr instanceof Assign)) {
|
||||
continue;
|
||||
}
|
||||
/** @var Assign $oAssignation */
|
||||
$oAssignation = $oNode->expr;
|
||||
|
||||
if (false === ($oAssignation->var instanceof Variable)) {
|
||||
continue;
|
||||
}
|
||||
if (false === ($oAssignation->expr instanceof PhpParser\Node\Expr\Array_)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sCurrentRootVar = $oAssignation->var->name;
|
||||
if (!array_key_exists($sCurrentRootVar, $this->aVarsMap))
|
||||
{
|
||||
if (!array_key_exists($sCurrentRootVar, $this->aVarsMap)) {
|
||||
continue;
|
||||
}
|
||||
$aCurrentRootVarMap =& $this->aVarsMap[$sCurrentRootVar];
|
||||
|
||||
foreach ($oAssignation->expr->items as $oItem)
|
||||
{
|
||||
foreach ($oAssignation->expr->items as $oItem) {
|
||||
$sValue = $prettyPrinter->prettyPrintExpr($oItem->value);
|
||||
$aCurrentRootVarMap[$oItem->key->value] = $sValue;
|
||||
}
|
||||
|
||||
@@ -539,8 +539,25 @@ class FileLog
|
||||
*/
|
||||
class LogChannels
|
||||
{
|
||||
const APC = 'apc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.7.7 N°4558 use this new channel when logging DB transactions
|
||||
*/
|
||||
const CMDB_SOURCE = 'cmdbsource';
|
||||
|
||||
const DEADLOCK = 'DeadLock';
|
||||
|
||||
const INLINE_IMAGE = 'InlineImage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1 N°4849
|
||||
* @since 2.7.7 N°4635
|
||||
*/
|
||||
const NOTIFICATIONS = 'notifications';
|
||||
|
||||
const PORTAL = 'portal';
|
||||
}
|
||||
|
||||
@@ -681,7 +698,7 @@ abstract class LogAPI
|
||||
|
||||
if (isset($sLogLevelMin[static::CHANNEL_DEFAULT]))
|
||||
{
|
||||
return $sLogLevelMin[$sChannel];
|
||||
return $sLogLevelMin[static::CHANNEL_DEFAULT];
|
||||
}
|
||||
|
||||
return static::LEVEL_DEFAULT;
|
||||
|
||||
@@ -589,10 +589,10 @@ abstract class MetaModel
|
||||
* @param string $sRuleId
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* @since 2.6.1 N°1968 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* definition of the rule in the hierarchy
|
||||
*/
|
||||
final private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)
|
||||
private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)
|
||||
{
|
||||
foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sClass)
|
||||
{
|
||||
@@ -7330,9 +7330,11 @@ abstract class MetaModel
|
||||
* @param string $sInput
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return mixed
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function ApplyParams($sInput, $aParams)
|
||||
public static function ApplyParams($sInput, $aParams)
|
||||
{
|
||||
$aParams = static::AddMagicPlaceholders($aParams);
|
||||
|
||||
@@ -7342,14 +7344,11 @@ abstract class MetaModel
|
||||
|
||||
$aSearches = array();
|
||||
$aReplacements = array();
|
||||
foreach($aParams as $sSearch => $replace)
|
||||
{
|
||||
foreach ($aParams as $sSearch => $replace) {
|
||||
// Some environment parameters are objects, we just need scalars
|
||||
if (is_object($replace))
|
||||
{
|
||||
if (is_object($replace)) {
|
||||
$iPos = strpos($sSearch, '->object()');
|
||||
if ($iPos !== false)
|
||||
{
|
||||
if ($iPos !== false) {
|
||||
// Expand the parameters for the object
|
||||
$sName = substr($sSearch, 0, $iPos);
|
||||
// Note: Capturing
|
||||
@@ -7357,63 +7356,67 @@ abstract class MetaModel
|
||||
// 2 - The arrow
|
||||
// 3 - The attribute code
|
||||
$aRegExps = array(
|
||||
'/(\\$)'.$sName.'-(>|>)([^\\$]+)\\$/', // Support both syntaxes: $this->xxx$ or $this->xxx$ for HTML compatibility
|
||||
'/(%24)'.$sName.'-(>|>)([^%24]+)%24/', // Support for urlencoded in HTML attributes (%20this->xxx%20)
|
||||
);
|
||||
foreach($aRegExps as $sRegExp)
|
||||
{
|
||||
if(preg_match_all($sRegExp, $sInput, $aMatches))
|
||||
{
|
||||
foreach($aMatches[3] as $idx => $sPlaceholderAttCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sReplacement = $replace->GetForTemplate($sPlaceholderAttCode);
|
||||
if($sReplacement !== null)
|
||||
{
|
||||
$aReplacements[] = $sReplacement;
|
||||
$aSearches[] = $aMatches[1][$idx] . $sName . '-' . $aMatches[2][$idx] . $sPlaceholderAttCode . $aMatches[1][$idx];
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// No replacement will occur
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
'/(\\$)'.$sName.'-(>|>)([^\\$]+)\\$/', // Support both syntaxes: $this->xxx$ or $this->xxx$ for HTML compatibility
|
||||
'/(%24)'.$sName.'-(>|>)([^%24]+)%24/', // Support for urlencoded in HTML attributes (%20this->xxx%20)
|
||||
);
|
||||
foreach ($aRegExps as $sRegExp) {
|
||||
if (preg_match_all($sRegExp, $sInput, $aMatches)) {
|
||||
foreach ($aMatches[3] as $idx => $sPlaceholderAttCode) {
|
||||
try {
|
||||
$sReplacement = $replace->GetForTemplate($sPlaceholderAttCode);
|
||||
if ($sReplacement !== null) {
|
||||
$aReplacements[] = $sReplacement;
|
||||
$aSearches[] = $aMatches[1][$idx].$sName.'-'.$aMatches[2][$idx].$sPlaceholderAttCode.$aMatches[1][$idx];
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$aContext = [
|
||||
'placeholder' => $sPlaceholderAttCode,
|
||||
'replace class' => get_class($replace),
|
||||
];
|
||||
if ($replace instanceof DBObject) {
|
||||
$aContext['replace id'] = $replace->GetKey();
|
||||
}
|
||||
IssueLog::Debug(
|
||||
'Invalid placeholder in notification, no replacement will occur!',
|
||||
LogChannels::NOTIFICATIONS,
|
||||
$aContext
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue; // Ignore this non-scalar value
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aRegExps = array(
|
||||
'/(\$)'.$sSearch.'\$/', // Support for regular placeholders (eg. $APP_URL$)
|
||||
'/(%24)'.$sSearch.'%24/', // Support for urlencoded in HTML attributes (eg. %24APP_URL%24)
|
||||
);
|
||||
foreach($aRegExps as $sRegExp)
|
||||
{
|
||||
if(preg_match_all($sRegExp, $sInput, $aMatches))
|
||||
{
|
||||
foreach($aMatches[1] as $idx => $sDelimiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
$aReplacements[] = (string) $replace;
|
||||
$aSearches[] = $aMatches[1][$idx] . $sSearch . $aMatches[1][$idx];
|
||||
foreach ($aRegExps as $sRegExp) {
|
||||
if (preg_match_all($sRegExp, $sInput, $aMatches)) {
|
||||
foreach ($aMatches[1] as $idx => $sDelimiter) {
|
||||
try {
|
||||
$aReplacements[] = (string)$replace;
|
||||
$aSearches[] = $aMatches[1][$idx].$sSearch.$aMatches[1][$idx];
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// No replacement will occur
|
||||
catch (Exception $e) {
|
||||
IssueLog::Debug(
|
||||
'Invalid placeholder in notification, no replacement will occur !',
|
||||
LogChannels::NOTIFICATIONS,
|
||||
[
|
||||
'placeholder' => $sPlaceholderAttCode,
|
||||
'replace' => $replace,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str_replace($aSearches, $aReplacements, $sInput);
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ final class ormTagSet extends ormSet
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of tags indexed by code
|
||||
* @return array index: code, value: corresponding {@see \TagSetFieldData}
|
||||
*/
|
||||
public function GetTags()
|
||||
{
|
||||
|
||||
@@ -25,6 +25,19 @@
|
||||
|
||||
class PDFBulkExport extends HTMLBulkExport
|
||||
{
|
||||
/**
|
||||
* @var string For sample purposes
|
||||
* @internal
|
||||
* @since 2.7.8
|
||||
*/
|
||||
const ENUM_OUTPUT_TYPE_SAMPLE = 'sample';
|
||||
/**
|
||||
* @var string For the real export
|
||||
* @internal
|
||||
* @since 2.7.8
|
||||
*/
|
||||
const ENUM_OUTPUT_TYPE_REAL = 'real';
|
||||
|
||||
public function DisplayUsage(Page $oP)
|
||||
{
|
||||
$oP->p(" * pdf format options:");
|
||||
@@ -190,6 +203,25 @@ EOF
|
||||
return $sPDF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 2.7.8
|
||||
*/
|
||||
protected function GetSampleData($oObj, $sAttCode)
|
||||
{
|
||||
if ($sAttCode !== 'id')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
|
||||
// As sample data will be displayed in the web browser, AttributeImage needs to be rendered with a regular HTML format, meaning its "src" looking like "data:image/png;base64,iVBORw0KGgoAAAANSUh..."
|
||||
// Whereas for the PDF generation it needs to be rendered with a TCPPDF-compatible format, meaning its "src" looking like "@iVBORw0KGgoAAAANSUh..."
|
||||
if ($oAttDef instanceof AttributeImage) {
|
||||
return $this->GetAttributeImageValue($oAttDef, $oObj->Get($sAttCode), static::ENUM_OUTPUT_TYPE_SAMPLE);
|
||||
}
|
||||
}
|
||||
return parent::GetSampleData($oObj, $sAttCode);
|
||||
}
|
||||
|
||||
protected function GetValue($oObj, $sAttCode)
|
||||
{
|
||||
switch($sAttCode)
|
||||
@@ -205,31 +237,7 @@ EOF
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ($oAttDef instanceof AttributeImage)
|
||||
{
|
||||
// To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect
|
||||
//
|
||||
$iDefaultMaxWidthPx = 48;
|
||||
$iDefaultMaxHeightPx = 48;
|
||||
if ($value->IsEmpty())
|
||||
{
|
||||
$iNewWidth = $iDefaultMaxWidthPx;
|
||||
$iNewHeight = $iDefaultMaxHeightPx;
|
||||
|
||||
$sUrl = $oAttDef->Get('default_image');
|
||||
}
|
||||
else
|
||||
{
|
||||
list($iWidth, $iHeight) = utils::GetImageSize($value->GetData());
|
||||
$iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width'));
|
||||
$iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height'));
|
||||
|
||||
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight);
|
||||
$iNewWidth = $iWidth * $fScale;
|
||||
$iNewHeight = $iHeight * $fScale;
|
||||
|
||||
$sUrl = 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData());
|
||||
}
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="width: '.$iNewWidth.'px; height: '.$iNewHeight.'px">' : '';
|
||||
$sRet = '<div class="view-image">'.$sRet.'</div>';
|
||||
$sRet = $this->GetAttributeImageValue($oAttDef, $value, static::ENUM_OUTPUT_TYPE_REAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -258,4 +266,53 @@ EOF
|
||||
{
|
||||
return 'pdf';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \AttributeImage $oAttDef Instance of image attribute
|
||||
* @param \ormDocument $oValue Value of image attribute
|
||||
* @param string $sOutputType {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_SAMPLE}, {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_REAL}
|
||||
*
|
||||
* @return string Rendered value of $oAttDef / $oValue according to the desired $sOutputType
|
||||
* @since 2.7.8
|
||||
*/
|
||||
protected function GetAttributeImageValue(AttributeImage $oAttDef, ormDocument $oValue, string $sOutputType)
|
||||
{
|
||||
// To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect
|
||||
//
|
||||
$iDefaultMaxWidthPx = 48;
|
||||
$iDefaultMaxHeightPx = 48;
|
||||
if ($oValue->IsEmpty()) {
|
||||
$iNewWidth = $iDefaultMaxWidthPx;
|
||||
$iNewHeight = $iDefaultMaxHeightPx;
|
||||
|
||||
$sUrl = $oAttDef->Get('default_image');
|
||||
} else {
|
||||
list($iWidth, $iHeight) = utils::GetImageSize($oValue->GetData());
|
||||
$iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width'));
|
||||
$iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height'));
|
||||
|
||||
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight);
|
||||
$iNewWidth = $iWidth * $fScale;
|
||||
$iNewHeight = $iHeight * $fScale;
|
||||
|
||||
$sValueAsBase64 = base64_encode($oValue->GetData());
|
||||
switch ($sOutputType) {
|
||||
case static::ENUM_OUTPUT_TYPE_SAMPLE:
|
||||
$sUrl = 'data:'.$oValue->GetMimeType().';base64,'.$sValueAsBase64;
|
||||
break;
|
||||
|
||||
case static::ENUM_OUTPUT_TYPE_REAL:
|
||||
default:
|
||||
// TCPDF requires base64-encoded images to be rendered without the usual "data:<MIMETYPE>;base64" header but with an "@"
|
||||
// @link https://tcpdf.org/examples/example_009/
|
||||
$sUrl = '@'.$sValueAsBase64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="width: '.$iNewWidth.'px; height: '.$iNewHeight.'px; vertical-align: middle; text-align:center;">' : '';
|
||||
$sRet = '<div class="view-image">'.$sRet.'</div>';
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ EOF
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeTagSet)
|
||||
{
|
||||
$sField = $oObj->GetAsCSV($sAttCode, $this->bLocalizeOutput, '');
|
||||
$sField = utils::HtmlEntities($oObj->GetAsCSV($sAttCode, $this->bLocalizeOutput, ''));
|
||||
$sData .= "<td x:str>$sField</td>";
|
||||
}
|
||||
else
|
||||
|
||||
@@ -491,7 +491,17 @@ class SQLObjectQuery extends SQLQuery
|
||||
}
|
||||
}
|
||||
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias = '', $aJoinData)
|
||||
/**
|
||||
* @param \SQLObjectQuery $oRootQuery
|
||||
* @param $aFrom
|
||||
* @param $sCallerAlias
|
||||
* @param $aJoinData
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $sCallerAlias for PHP 8.0 compat (Private method with only 2 calls in the class, both providing the optional parameter)
|
||||
*/
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias, $aJoinData)
|
||||
{
|
||||
$aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias;
|
||||
$sJoinCond = '';
|
||||
@@ -610,6 +620,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
/** @var \SQLObjectQuery $oRightSelect */
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
|
||||
$oRightSelect->PrepareSingleTable($oRootQuery, $aTempFrom, $this->m_sTableAlias, $aJoinData);
|
||||
|
||||
@@ -263,6 +263,7 @@ abstract class TriggerOnObject extends Trigger
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSearch->AddCondition('id', $iObjectId, '=');
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$bRet = ($oSet->Count() > 0);
|
||||
}
|
||||
|
||||
@@ -952,6 +952,21 @@ class UserRights
|
||||
return self::$m_oRealUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string ID of the connected user : if impersonate then use {@see m_oRealUser}, else {@see m_oUser}. If no user set then return ''
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 method creation
|
||||
*/
|
||||
public static function GetConnectedUserId() {
|
||||
if (false === is_null(static::$m_oRealUser)) {
|
||||
return static::$m_oRealUser->GetKey();
|
||||
}
|
||||
if (false === is_null(static::$m_oUser)) {
|
||||
return static::$m_oUser->GetKey();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function GetRealUserId()
|
||||
{
|
||||
if (is_null(self::$m_oRealUser))
|
||||
@@ -1212,7 +1227,7 @@ class UserRights
|
||||
elseif ((self::$m_oUser !== null) && ($oUser->GetKey() == self::$m_oUser->GetKey()))
|
||||
{
|
||||
// Data about the current user can be found into the session data
|
||||
if (array_key_exists('profile_list', $_SESSION))
|
||||
if ((false === utils::IsModeCLI()) && array_key_exists('profile_list', $_SESSION))
|
||||
{
|
||||
$aProfiles = $_SESSION['profile_list'];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.7.5";
|
||||
$version: "v2.7.8";
|
||||
$approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css
|
||||
|
||||
// Base colors
|
||||
|
||||
@@ -2424,26 +2424,33 @@ fieldset .details>.field_container {
|
||||
|
||||
.selectize-dropdown,
|
||||
.selectize-input,
|
||||
.selectize-input input{
|
||||
font-size: 12px;
|
||||
}
|
||||
.selectize-input{
|
||||
padding: 2px 2px 0px 2px; /* padding-bottom = padding-top - item margin-bottom */
|
||||
border: 1px solid #ABABAB;
|
||||
border-radius: 0;
|
||||
.selectize-input input {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.attribute-set-item.partial-code{
|
||||
color: transparentize($gray-darker, 0.4);
|
||||
background-color: lighten($gray-lighter, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.selectize-input {
|
||||
padding: 2px 2px 0px 2px; /* padding-bottom = padding-top - item margin-bottom */
|
||||
border: 1px solid #ABABAB;
|
||||
border-radius: 0;
|
||||
|
||||
.attribute-set-item.partial-code {
|
||||
color: transparentize($gray-darker, 0.4);
|
||||
background-color: lighten($gray-lighter, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-attribute-type="AttributeDuration"] {
|
||||
.field_value_container {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
.one-col-details .details .field_container.field_small {
|
||||
div.field_label {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=custom-theme&bgImgOpacityError=18&bgImgOpacityHighlight=75&bgImgOpacityActive=65&bgImgOpacityHover=100&bgImgOpacityDefault=100&bgImgOpacityContent=100&bgImgOpacityHeader=35&cornerRadiusShadow=5px&offsetLeftShadow=-5px&offsetTopShadow=-5px&thicknessShadow=5px&opacityShadow=20&bgImgOpacityShadow=10&bgTextureShadow=flat&bgColorShadow=%23000000&opacityOverlay=50&bgImgOpacityOverlay=20&bgTextureOverlay=diagonals_thick&bgColorOverlay=%23666666&iconColorError=%23ffd27a&fcError=%23ffffff&borderColorError=%23cd0a0a&bgTextureError=diagonals_thick&bgColorError=%23b81900&iconColorHighlight=%231c94c4&fcHighlight=%23363636&borderColorHighlight=%23fed22f&bgTextureHighlight=flat&bgColorHighlight=%23ffe45c&iconColorActive=%23E87C1E&fcActive=%23E87C1E&borderColorActive=%23E87C1E&bgTextureActive=flat&bgColorActive=%23ffffff&iconColorHover=%23E87C1E&fcHover=%23E87C1E&borderColorHover=%23E87C1E&bgTextureHover=flat&bgColorHover=%23fde17c&iconColorDefault=%23F26522&fcDefault=%23555555&borderColorDefault=%23cccccc&bgTextureDefault=flat&bgColorDefault=%23f1f1f1&iconColorContent=%23222222&fcContent=%23333333&borderColorContent=%23dddddd&bgTextureContent=flat&bgColorContent=%23eeeeee&iconColorHeader=%23ffffff&fcHeader=%23ffffff&borderColorHeader=%23F26522&bgTextureHeader=flat&bgColorHeader=%23E87C1E&cornerRadius=0&fwDefault=bold&fsDefault=1.1em&ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif
|
||||
* Copyright jQuery Foundation and other contributors; Licensed MIT
|
||||
* The original css file has been scssized (through www.css2scss.com)
|
||||
*
|
||||
* Other modification done : replaced the `Alpha(` by `alpha(` to avoid warnings generated by SCSSPHP
|
||||
*/
|
||||
.ui-draggable-handle {
|
||||
-ms-touch-action: none;
|
||||
@@ -46,26 +48,27 @@
|
||||
}
|
||||
}
|
||||
.ui-helper-zfix {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
filter: Alpha(Opacity=0);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
filter: alpha(Opacity=0);
|
||||
}
|
||||
.ui-front {
|
||||
z-index: 100;
|
||||
}
|
||||
.ui-state-disabled {
|
||||
cursor: default !important;
|
||||
pointer-events: none;
|
||||
opacity: .35;
|
||||
filter: Alpha(Opacity=35);
|
||||
background-image: none;
|
||||
.ui-icon {
|
||||
filter: Alpha(Opacity=35);
|
||||
}
|
||||
cursor: default !important;
|
||||
pointer-events: none;
|
||||
opacity: .35;
|
||||
filter: alpha(Opacity=35);
|
||||
background-image: none;
|
||||
|
||||
.ui-icon {
|
||||
filter: alpha(Opacity=35);
|
||||
}
|
||||
}
|
||||
.ui-icon {
|
||||
display: inline-block;
|
||||
@@ -86,14 +89,14 @@
|
||||
display: block;
|
||||
}
|
||||
.ui-widget-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #666666 url($approot-relative + "css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=" + $version) 50% 50% repeat;
|
||||
opacity: .5;
|
||||
filter: Alpha(Opacity=50);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #666666 url($approot-relative + "css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=" + $version) 50% 50% repeat;
|
||||
opacity: .5;
|
||||
filter: alpha(Opacity=50);
|
||||
}
|
||||
.ui-resizable {
|
||||
position: relative;
|
||||
@@ -1069,14 +1072,14 @@ body {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-priority-secondary {
|
||||
opacity: .7;
|
||||
filter: Alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
opacity: .7;
|
||||
filter: alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui-state-disabled {
|
||||
opacity: .35;
|
||||
filter: Alpha(Opacity=35);
|
||||
background-image: none;
|
||||
opacity: .35;
|
||||
filter: alpha(Opacity=35);
|
||||
background-image: none;
|
||||
}
|
||||
.ui-icon {
|
||||
background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_222222_256x240.png?v=" + $version);
|
||||
@@ -1137,14 +1140,14 @@ body {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-priority-secondary {
|
||||
opacity: .7;
|
||||
filter: Alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
opacity: .7;
|
||||
filter: alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui-state-disabled {
|
||||
opacity: .35;
|
||||
filter: Alpha(Opacity=35);
|
||||
background-image: none;
|
||||
opacity: .35;
|
||||
filter: alpha(Opacity=35);
|
||||
background-image: none;
|
||||
}
|
||||
.ui-icon {
|
||||
background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_ffffff_256x240.png?v=" + $version);
|
||||
@@ -1341,9 +1344,9 @@ a {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-priority-secondary {
|
||||
opacity: .7;
|
||||
filter: Alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
opacity: .7;
|
||||
filter: alpha(Opacity=70);
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui-icon-blank {
|
||||
background-position: 16px 16px;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"require" : {
|
||||
"apereo/phpcas" : "~1.3"
|
||||
}
|
||||
"config" : {
|
||||
"classmap-authoritative" : true
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4" : {
|
||||
"Combodo\\iTop\\Cas\\" : "src"
|
||||
}
|
||||
},
|
||||
"require" : {
|
||||
"apereo/phpcas" : "~1.6.0"
|
||||
}
|
||||
}
|
||||
86
datamodels/2.x/authent-cas/composer.lock
generated
86
datamodels/2.x/authent-cas/composer.lock
generated
@@ -4,28 +4,32 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "4db4df78154f0de344ba35a27fe766b7",
|
||||
"content-hash": "46afbbe7e92c2ccfe403f366ef1877e5",
|
||||
"packages": [
|
||||
{
|
||||
"name": "apereo/phpcas",
|
||||
"version": "1.3.7",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/apereo/phpCAS.git",
|
||||
"reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082"
|
||||
"reference": "f817c72a961484afef95ac64a9257c8e31f063b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/apereo/phpCAS/zipball/b5b29102c3a42f570c4a3e852f3cf67cae6d6082",
|
||||
"reference": "b5b29102c3a42f570c4a3e852f3cf67cae6d6082",
|
||||
"url": "https://api.github.com/repos/apereo/phpCAS/zipball/f817c72a961484afef95ac64a9257c8e31f063b9",
|
||||
"reference": "f817c72a961484afef95ac64a9257c8e31f063b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": ">=5.4.0"
|
||||
"ext-dom": "*",
|
||||
"php": ">=7.1.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7.10"
|
||||
"monolog/monolog": "^1.0.0 || ^2.0.0",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"phpunit/phpunit": ">=7.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -45,11 +49,16 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Joachim Fritschi",
|
||||
"homepage": "https://wiki.jasig.org/display/~fritschi"
|
||||
"email": "jfritschi@freenet.de",
|
||||
"homepage": "https://github.com/jfritschi"
|
||||
},
|
||||
{
|
||||
"name": "Adam Franco",
|
||||
"homepage": "https://wiki.jasig.org/display/~adamfranco"
|
||||
"homepage": "https://github.com/adamfranco"
|
||||
},
|
||||
{
|
||||
"name": "Henry Pan",
|
||||
"homepage": "https://github.com/phy25"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple API for authenticating users against a CAS server",
|
||||
@@ -59,7 +68,61 @@
|
||||
"cas",
|
||||
"jasig"
|
||||
],
|
||||
"time": "2019-04-22T19:48:16+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/apereo/phpCAS/issues",
|
||||
"source": "https://github.com/apereo/phpCAS/tree/1.6.0"
|
||||
},
|
||||
"time": "2022-10-31T20:39:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "Psr/Log/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
||||
},
|
||||
"time": "2021-05-03T11:20:27+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
@@ -69,5 +132,6 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.1.0"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* Localized data
|
||||
/**
|
||||
* Spanish Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2013 XXXXX
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @traductor Miguel Turrubiates <miguel_tf@yahoo.com>
|
||||
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
|
||||
*/
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
|
||||
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
|
||||
'CAS:Login:SignIn' => 'Sign in with CAS~~',
|
||||
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
|
||||
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'CAS:Error:UserNotAllowed' => 'Usuario no permitido',
|
||||
'CAS:Login:SignIn' => 'Iniciar sesión con CAS',
|
||||
'CAS:Login:SignInTooltip' => 'Click para autenticarse con servidor CAS',
|
||||
));
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__.'/vendor/autoload.php';
|
||||
require_once __DIR__.'/src/Config.php';
|
||||
require_once __DIR__.'/src/CASLoginExtension.php';
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-cas/2.7.5',
|
||||
'authent-cas/2.7.8',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -24,7 +24,8 @@ SetupWebPage::AddModule(
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.authent-cas.php',
|
||||
'main.php'
|
||||
'vendor/autoload.php',
|
||||
'src/CASLoginExtension.php',
|
||||
),
|
||||
'webservice' => array(
|
||||
|
||||
@@ -50,6 +51,7 @@ SetupWebPage::AddModule(
|
||||
'cas_port' => '',
|
||||
'cas_context' => '',
|
||||
'cas_version' => '',
|
||||
'service_base_url' => '',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
17
datamodels/2.x/authent-cas/src/CASLog.php
Normal file
17
datamodels/2.x/authent-cas/src/CASLog.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Cas;
|
||||
|
||||
use LogAPI;
|
||||
|
||||
class CASLog extends LogAPI
|
||||
{
|
||||
const CHANNEL_DEFAULT = 'CASLog';
|
||||
|
||||
protected static $m_oFileLog = null;
|
||||
}
|
||||
|
||||
81
datamodels/2.x/authent-cas/src/CASLogger.php
Normal file
81
datamodels/2.x/authent-cas/src/CASLogger.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Cas;
|
||||
|
||||
use IssueLog;
|
||||
use LogAPI;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
class CASLogger implements LoggerInterface
|
||||
{
|
||||
public function __construct($sDebugFile)
|
||||
{
|
||||
CASLog::Enable($sDebugFile);
|
||||
}
|
||||
|
||||
const LEVEL_COMPAT = [
|
||||
LogLevel::EMERGENCY => LogAPI::LEVEL_ERROR,
|
||||
LogLevel::ALERT => LogAPI::LEVEL_ERROR,
|
||||
LogLevel::CRITICAL => LogAPI::LEVEL_ERROR,
|
||||
LogLevel::ERROR => LogAPI::LEVEL_ERROR,
|
||||
LogLevel::WARNING => LogAPI::LEVEL_WARNING,
|
||||
LogLevel::NOTICE => LogAPI::LEVEL_INFO,
|
||||
LogLevel::INFO => LogAPI::LEVEL_INFO,
|
||||
LogLevel::DEBUG => LogAPI::LEVEL_DEBUG,
|
||||
];
|
||||
|
||||
public function emergency($message, array $context = array())
|
||||
{
|
||||
CASLog::Error('EMERGENCY: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
IssueLog::Error('EMERGENCY: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function alert($message, array $context = array())
|
||||
{
|
||||
CASLog::Error('ALERT: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
IssueLog::Error('ALERT: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function critical($message, array $context = array())
|
||||
{
|
||||
CASLog::Error('CRITICAL: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
IssueLog::Error('CRITICAL: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function error($message, array $context = array())
|
||||
{
|
||||
CASLog::Error('ERROR: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
IssueLog::Error('ERROR: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function warning($message, array $context = array())
|
||||
{
|
||||
CASLog::Warning('WARNING: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function notice($message, array $context = array())
|
||||
{
|
||||
CASLog::Info('NOTICE: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function info($message, array $context = array())
|
||||
{
|
||||
CASLog::Info('INFO: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function debug($message, array $context = array())
|
||||
{
|
||||
CASLog::Debug('DEBUG: '.$message, CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
|
||||
public function log($level, $message, array $context = array())
|
||||
{
|
||||
$sLevel = self::LEVEL_COMPAT[$level] ?? LogAPI::LEVEL_ERROR;
|
||||
CASLog::Log($sLevel, strtoupper($level).": $message", CASLog::CHANNEL_DEFAULT, $context);
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$bCASDebug = Config::Get('cas_debug');
|
||||
if ($bCASDebug)
|
||||
{
|
||||
phpCAS::setDebug(APPROOT.'log/cas.log');
|
||||
phpCAS::setLogger(new CASLogger(APPROOT.'log/cas.log'));
|
||||
}
|
||||
|
||||
// Initialize phpCAS
|
||||
@@ -162,7 +162,8 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$sCASHost = Config::Get('cas_host');
|
||||
$iCASPort = Config::Get('cas_port');
|
||||
$sCASContext = Config::Get('cas_context');
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
|
||||
$sServiceBaseURL = Config::Get('service_base_url', self::GetServiceBaseURL());
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, $sServiceBaseURL, false /* session already started */);
|
||||
$sCASCACertPath = Config::Get('cas_server_ca_cert_path');
|
||||
if (empty($sCASCACertPath))
|
||||
{
|
||||
@@ -178,6 +179,38 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
}
|
||||
}
|
||||
|
||||
private static function GetServiceBaseURL()
|
||||
{
|
||||
$protocol = $_SERVER['REQUEST_SCHEME'];
|
||||
$protocol .= '://';
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
|
||||
// explode the host list separated by comma and use the first host
|
||||
$hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
|
||||
// see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default
|
||||
return $protocol . $hosts[0];
|
||||
} else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
|
||||
$server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
|
||||
} else {
|
||||
if (empty($_SERVER['SERVER_NAME'])) {
|
||||
$server_url = $_SERVER['HTTP_HOST'];
|
||||
} else {
|
||||
$server_url = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
}
|
||||
if (!strpos($server_url, ':')) {
|
||||
if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
|
||||
$server_port = $_SERVER['SERVER_PORT'];
|
||||
} else {
|
||||
$ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);
|
||||
$server_port = $ports[0];
|
||||
}
|
||||
|
||||
$server_url .= ':';
|
||||
$server_url .= $server_port;
|
||||
}
|
||||
return $protocol . $server_url;
|
||||
}
|
||||
|
||||
private function DoUserProvisioning($sLogin)
|
||||
{
|
||||
$bCASUserSynchro = Config::Get('cas_user_synchro');
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS.php
|
||||
* @category Authentication
|
||||
@@ -27,4 +27,6 @@
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__).'/source/CAS.php';
|
||||
require_once __DIR__.'/source/CAS.php';
|
||||
|
||||
trigger_error('Including CAS.php is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);
|
||||
|
||||
@@ -6,22 +6,21 @@ users via a Central Authentication Service (CAS) server.
|
||||
|
||||
Please see the wiki website for more information:
|
||||
|
||||
https://wiki.jasig.org/display/CASC/phpCAS
|
||||
https://apereo.github.io/phpCAS/
|
||||
|
||||
Api documentation can be found here:
|
||||
|
||||
https://apereo.github.io/phpCAS/
|
||||
https://apereo.github.io/phpCAS/api/
|
||||
|
||||
|
||||
[](https://travis-ci.org/apereo/phpCAS)
|
||||
|
||||
[](https://github.com/apereo/phpCAS/actions/workflows/test.yml)
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
Copyright 2007-2015, JA-SIG, Inc.
|
||||
This project includes software developed by Jasig.
|
||||
http://www.jasig.org/
|
||||
Copyright 2007-2020, Apereo Foundation.
|
||||
This project includes software developed by Apereo Foundation.
|
||||
http://www.apereo.org/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this software except in compliance with the License.
|
||||
|
||||
@@ -1,29 +1,55 @@
|
||||
{
|
||||
"name": "apereo/phpcas",
|
||||
"description": "Provides a simple API for authenticating users against a CAS server",
|
||||
"keywords": ["cas", "jasig", "apereo"],
|
||||
"homepage": "https://wiki.jasig.org/display/CASC/phpCAS",
|
||||
"type": "library",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{"name": "Joachim Fritschi", "homepage": "https://wiki.jasig.org/display/~fritschi"},
|
||||
{"name": "Adam Franco", "homepage": "https://wiki.jasig.org/display/~adamfranco"}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"ext-curl": "*"
|
||||
"name" : "apereo/phpcas",
|
||||
"description" : "Provides a simple API for authenticating users against a CAS server",
|
||||
"keywords" : [
|
||||
"cas",
|
||||
"jasig",
|
||||
"apereo"
|
||||
],
|
||||
"homepage" : "https://wiki.jasig.org/display/CASC/phpCAS",
|
||||
"type" : "library",
|
||||
"license" : "Apache-2.0",
|
||||
"authors" : [{
|
||||
"name" : "Joachim Fritschi",
|
||||
"homepage" : "https://github.com/jfritschi",
|
||||
"email" : "jfritschi@freenet.de"
|
||||
}, {
|
||||
"name" : "Adam Franco",
|
||||
"homepage" : "https://github.com/adamfranco"
|
||||
}, {
|
||||
"name" : "Henry Pan",
|
||||
"homepage" : "https://github.com/phy25"
|
||||
}
|
||||
],
|
||||
"require" : {
|
||||
"php" : ">=7.1.0",
|
||||
"ext-curl" : "*",
|
||||
"ext-dom" : "*",
|
||||
"psr/log" : "^1.0 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7.10"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"source/"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
}
|
||||
"require-dev" : {
|
||||
"monolog/monolog" : "^1.0.0 || ^2.0.0",
|
||||
"phpunit/phpunit" : ">=7.5",
|
||||
"phpstan/phpstan" : "^1.5"
|
||||
},
|
||||
"autoload" : {
|
||||
"classmap" : [
|
||||
"source/"
|
||||
]
|
||||
},
|
||||
"autoload-dev" : {
|
||||
"files": ["source/CAS.php"],
|
||||
"psr-4" : {
|
||||
"PhpCas\\" : "test/CAS/"
|
||||
}
|
||||
},
|
||||
"scripts" : {
|
||||
"test" : "phpunit",
|
||||
"phpstan" : "phpstan"
|
||||
},
|
||||
"extra" : {
|
||||
"branch-alias" : {
|
||||
"dev-master" : "1.3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*
|
||||
*
|
||||
* Interface class of the phpCAS library
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/CAS.php
|
||||
* @category Authentication
|
||||
@@ -35,6 +35,7 @@
|
||||
* @ingroup public
|
||||
*/
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
//
|
||||
// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']
|
||||
@@ -44,11 +45,6 @@ if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($
|
||||
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
|
||||
// Add a E_USER_DEPRECATED for php versions <= 5.2
|
||||
if (!defined('E_USER_DEPRECATED')) {
|
||||
define('E_USER_DEPRECATED', E_USER_NOTICE);
|
||||
}
|
||||
|
||||
|
||||
// ########################################################################
|
||||
// CONSTANTS
|
||||
@@ -61,7 +57,7 @@ if (!defined('E_USER_DEPRECATED')) {
|
||||
/**
|
||||
* phpCAS version. accessible for the user by phpCAS::getVersion().
|
||||
*/
|
||||
define('PHPCAS_VERSION', '1.3.7');
|
||||
define('PHPCAS_VERSION', '1.6.0');
|
||||
|
||||
/**
|
||||
* @addtogroup public
|
||||
@@ -140,11 +136,6 @@ define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');
|
||||
*/
|
||||
define("SAML_ATTRIBUTES", 'SAMLATTRIBS');
|
||||
|
||||
/**
|
||||
* SAML Attributes
|
||||
*/
|
||||
define("DEFAULT_ERROR", 'Internal script failure');
|
||||
|
||||
/** @} */
|
||||
/**
|
||||
* @addtogroup publicPGTStorage
|
||||
@@ -224,6 +215,8 @@ define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese');
|
||||
define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish');
|
||||
define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan');
|
||||
define("PHPCAS_LANG_CHINESE_SIMPLIFIED", 'CAS_Languages_ChineseSimplified');
|
||||
define("PHPCAS_LANG_GALEGO", 'CAS_Languages_Galego');
|
||||
define("PHPCAS_LANG_PORTUGUESE", 'CAS_Languages_Portuguese');
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -261,7 +254,7 @@ define('DEFAULT_DEBUG_DIR', gettmpdir()."/");
|
||||
/** @} */
|
||||
|
||||
// include the class autoloader
|
||||
require_once dirname(__FILE__) . '/CAS/Autoload.php';
|
||||
require_once __DIR__ . '/CAS/Autoload.php';
|
||||
|
||||
/**
|
||||
* The phpCAS class is a simple container for the phpCAS library. It provides CAS
|
||||
@@ -330,12 +323,22 @@ class phpCAS
|
||||
/**
|
||||
* phpCAS client initializer.
|
||||
*
|
||||
* @param string $server_version the version of the CAS server
|
||||
* @param string $server_hostname the hostname of the CAS server
|
||||
* @param int $server_port the port the CAS server is running on
|
||||
* @param string $server_uri the URI the CAS server is responding on
|
||||
* @param bool $changeSessionID Allow phpCAS to change the session_id (Single
|
||||
* Sign Out/handleLogoutRequests is based on that change)
|
||||
* @param string $server_version the version of the CAS server
|
||||
* @param string $server_hostname the hostname of the CAS server
|
||||
* @param int $server_port the port the CAS server is running on
|
||||
* @param string $server_uri the URI the CAS server is responding on
|
||||
* @param string|string[]|CAS_ServiceBaseUrl_Interface
|
||||
* $service_base_url the base URL (protocol, host and the
|
||||
* optional port) of the CAS client; pass
|
||||
* in an array to use auto discovery with
|
||||
* an allowlist; pass in
|
||||
* CAS_ServiceBaseUrl_Interface for custom
|
||||
* behavior. Added in 1.6.0. Similar to
|
||||
* serverName config in other CAS clients.
|
||||
* @param bool $changeSessionID Allow phpCAS to change the session_id
|
||||
* (Single Sign Out/handleLogoutRequests
|
||||
* is based on that change)
|
||||
* @param \SessionHandlerInterface $sessionHandler the session handler
|
||||
*
|
||||
* @return void a newly created CAS_Client object
|
||||
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
|
||||
@@ -343,7 +346,8 @@ class phpCAS
|
||||
* and phpCAS::setDebug()).
|
||||
*/
|
||||
public static function client($server_version, $server_hostname,
|
||||
$server_port, $server_uri, $changeSessionID = true
|
||||
$server_port, $server_uri, $service_base_url,
|
||||
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
|
||||
) {
|
||||
phpCAS :: traceBegin();
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
@@ -362,8 +366,8 @@ class phpCAS
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri, $service_base_url,
|
||||
$changeSessionID, $sessionHandler
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
@@ -374,12 +378,22 @@ class phpCAS
|
||||
/**
|
||||
* phpCAS proxy initializer.
|
||||
*
|
||||
* @param string $server_version the version of the CAS server
|
||||
* @param string $server_hostname the hostname of the CAS server
|
||||
* @param int $server_port the port the CAS server is running on
|
||||
* @param string $server_uri the URI the CAS server is responding on
|
||||
* @param bool $changeSessionID Allow phpCAS to change the session_id (Single
|
||||
* Sign Out/handleLogoutRequests is based on that change)
|
||||
* @param string $server_version the version of the CAS server
|
||||
* @param string $server_hostname the hostname of the CAS server
|
||||
* @param string $server_port the port the CAS server is running on
|
||||
* @param string $server_uri the URI the CAS server is responding on
|
||||
* @param string|string[]|CAS_ServiceBaseUrl_Interface
|
||||
* $service_base_url the base URL (protocol, host and the
|
||||
* optional port) of the CAS client; pass
|
||||
* in an array to use auto discovery with
|
||||
* an allowlist; pass in
|
||||
* CAS_ServiceBaseUrl_Interface for custom
|
||||
* behavior. Added in 1.6.0. Similar to
|
||||
* serverName config in other CAS clients.
|
||||
* @param bool $changeSessionID Allow phpCAS to change the session_id
|
||||
* (Single Sign Out/handleLogoutRequests
|
||||
* is based on that change)
|
||||
* @param \SessionHandlerInterface $sessionHandler the session handler
|
||||
*
|
||||
* @return void a newly created CAS_Client object
|
||||
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
|
||||
@@ -387,7 +401,8 @@ class phpCAS
|
||||
* and phpCAS::setDebug()).
|
||||
*/
|
||||
public static function proxy($server_version, $server_hostname,
|
||||
$server_port, $server_uri, $changeSessionID = true
|
||||
$server_port, $server_uri, $service_base_url,
|
||||
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
|
||||
) {
|
||||
phpCAS :: traceBegin();
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
@@ -406,8 +421,8 @@ class phpCAS
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri, $service_base_url,
|
||||
$changeSessionID, $sessionHandler
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
@@ -435,6 +450,24 @@ class phpCAS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set/unset PSR-3 logger
|
||||
*
|
||||
* @param LoggerInterface $logger the PSR-3 logger used for logging, or
|
||||
* null to stop logging.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setLogger($logger = null)
|
||||
{
|
||||
if (empty(self::$_PHPCAS_DEBUG['unique_id'])) {
|
||||
self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
|
||||
}
|
||||
self::$_PHPCAS_DEBUG['logger'] = $logger;
|
||||
self::$_PHPCAS_DEBUG['indent'] = 0;
|
||||
phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/unset debug mode
|
||||
*
|
||||
@@ -442,9 +475,13 @@ class phpCAS
|
||||
* to stop debugging.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static function setDebug($filename = '')
|
||||
{
|
||||
trigger_error('phpCAS::setDebug() is deprecated in favor of phpCAS::setLogger().', E_USER_DEPRECATED);
|
||||
|
||||
if ($filename != false && gettype($filename) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');
|
||||
}
|
||||
@@ -518,14 +555,7 @@ class phpCAS
|
||||
$indent_str = ".";
|
||||
|
||||
|
||||
if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
|
||||
// Check if file exists and modifiy file permissions to be only
|
||||
// readable by the webserver
|
||||
if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
|
||||
touch(self::$_PHPCAS_DEBUG['filename']);
|
||||
// Chmod will fail on windows
|
||||
@chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
|
||||
}
|
||||
if (isset(self::$_PHPCAS_DEBUG['logger']) || !empty(self::$_PHPCAS_DEBUG['filename'])) {
|
||||
for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {
|
||||
|
||||
$indent_str .= '| ';
|
||||
@@ -533,7 +563,20 @@ class phpCAS
|
||||
// allow for multiline output with proper identing. Usefull for
|
||||
// dumping cas answers etc.
|
||||
$str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
|
||||
error_log(self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
|
||||
$str3 = self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2;
|
||||
if (isset(self::$_PHPCAS_DEBUG['logger'])) {
|
||||
self::$_PHPCAS_DEBUG['logger']->info($str3);
|
||||
}
|
||||
if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
|
||||
// Check if file exists and modifiy file permissions to be only
|
||||
// readable by the webserver
|
||||
if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
|
||||
touch(self::$_PHPCAS_DEBUG['filename']);
|
||||
// Chmod will fail on windows
|
||||
@chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
|
||||
}
|
||||
error_log($str3 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -567,8 +610,6 @@ class phpCAS
|
||||
}
|
||||
if (self::$_PHPCAS_VERBOSE) {
|
||||
echo "<br />\n<b>phpCAS error</b>: <font color=\"FF0000\"><b>" . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . "</b></font> in <b>" . $file . "</b> on line <b>" . $line . "</b><br />\n";
|
||||
} else {
|
||||
echo "<br />\n<b>Error</b>: <font color=\"FF0000\"><b>". DEFAULT_ERROR ."</b><br />\n";
|
||||
}
|
||||
phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line );
|
||||
phpCAS :: traceEnd();
|
||||
@@ -1869,6 +1910,14 @@ class phpCAS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CAS_Client
|
||||
*/
|
||||
public static function getCasClient()
|
||||
{
|
||||
return self::$_PHPCAS_CLIENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing purposes, use this method to set the client to a test double
|
||||
*
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/AuthenticationException.php
|
||||
* @category Authentication
|
||||
@@ -72,11 +72,15 @@ implements CAS_Exception
|
||||
phpCAS::traceBegin();
|
||||
$lang = $client->getLangObj();
|
||||
$client->printHTMLHeader($lang->getAuthenticationFailed());
|
||||
printf(
|
||||
$lang->getYouWereNotAuthenticated(),
|
||||
htmlentities($client->getURL()),
|
||||
isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
|
||||
);
|
||||
|
||||
if (phpCAS::getVerbose()) {
|
||||
printf(
|
||||
$lang->getYouWereNotAuthenticated(),
|
||||
htmlentities($client->getURL()),
|
||||
$_SERVER['SERVER_ADMIN'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
phpCAS::trace($messages[] = 'CAS URL: '.$cas_url);
|
||||
phpCAS::trace($messages[] = 'Authentication failure: '.$failure);
|
||||
if ( $no_response ) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* Autoloader Class
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Autoload.php
|
||||
* @category Authentication
|
||||
@@ -26,18 +26,24 @@ function CAS_autoload($class)
|
||||
// Static to hold the Include Path to CAS
|
||||
static $include_path;
|
||||
// Check only for CAS classes
|
||||
if (substr($class, 0, 4) !== 'CAS_') {
|
||||
if (substr($class, 0, 4) !== 'CAS_' && substr($class, 0, 7) !== 'PhpCas\\') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup the include path if it's not already set from a previous call
|
||||
if (empty($include_path)) {
|
||||
$include_path = array(dirname(dirname(__FILE__)), dirname(dirname(__FILE__)) . '/../test/' );
|
||||
$include_path = array(dirname(__DIR__));
|
||||
}
|
||||
|
||||
// Declare local variable to store the expected full path to the file
|
||||
|
||||
foreach ($include_path as $path) {
|
||||
$file_path = $path . '/' . str_replace('_', '/', $class) . '.php';
|
||||
$class_path = str_replace('_', DIRECTORY_SEPARATOR, $class);
|
||||
// PhpCas namespace mapping
|
||||
if (substr($class_path, 0, 7) === 'PhpCas\\') {
|
||||
$class_path = 'CAS' . DIRECTORY_SEPARATOR . substr($class_path, 7);
|
||||
}
|
||||
|
||||
$file_path = $path . DIRECTORY_SEPARATOR . $class_path . '.php';
|
||||
$fp = @fopen($file_path, 'r', true);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
@@ -54,6 +60,7 @@ function CAS_autoload($class)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$e = new Exception(
|
||||
'Class ' . $class . ' could not be loaded from ' .
|
||||
$file_path . ', file does not exist (Path="'
|
||||
@@ -61,22 +68,22 @@ function CAS_autoload($class)
|
||||
);
|
||||
$trace = $e->getTrace();
|
||||
if (isset($trace[2]) && isset($trace[2]['function'])
|
||||
&& in_array($trace[2]['function'], array('class_exists', 'interface_exists'))
|
||||
&& in_array($trace[2]['function'], array('class_exists', 'interface_exists', 'trait_exists'))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (isset($trace[1]) && isset($trace[1]['function'])
|
||||
&& in_array($trace[1]['function'], array('class_exists', 'interface_exists'))
|
||||
&& in_array($trace[1]['function'], array('class_exists', 'interface_exists', 'trait_exists'))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
die ((string) $e);
|
||||
}
|
||||
|
||||
// set up __autoload
|
||||
if (!(spl_autoload_functions())
|
||||
|| !in_array('CAS_autoload', spl_autoload_functions())
|
||||
) {
|
||||
// Set up autoload if not already configured by composer.
|
||||
if (!class_exists('CAS_Client'))
|
||||
{
|
||||
trigger_error('phpCAS autoloader is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);
|
||||
spl_autoload_register('CAS_autoload');
|
||||
if (function_exists('__autoload')
|
||||
&& !in_array('__autoload', spl_autoload_functions())
|
||||
@@ -86,5 +93,3 @@ if (!(spl_autoload_functions())
|
||||
spl_autoload_register('__autoload');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/CookieJar.php
|
||||
* @category Authentication
|
||||
@@ -231,6 +231,7 @@ class CAS_CookieJar
|
||||
case 'commenturl':
|
||||
case 'discard':
|
||||
case 'httponly':
|
||||
case 'samesite':
|
||||
$cookie[$attributeNameLC] = $attributeValue;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Exception.php
|
||||
* @category Authentication
|
||||
@@ -56,4 +56,4 @@ interface CAS_Exception
|
||||
{
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/GracefullTerminationException.php
|
||||
* @category Authentication
|
||||
@@ -83,4 +83,4 @@ implements CAS_Exception
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/InvalidArgumentException.php
|
||||
* @category Authentication
|
||||
@@ -43,4 +43,4 @@ implements CAS_Exception
|
||||
{
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Catalan.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/ChineseSimplified.php
|
||||
* @category Authentication
|
||||
@@ -111,4 +111,4 @@ class CAS_Languages_ChineseSimplified implements CAS_Languages_LanguageInterface
|
||||
{
|
||||
return '服务器 <b>%s</b> 不可用(<b>%s</b>)。';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/English.php
|
||||
* @category Authentication
|
||||
@@ -111,4 +111,4 @@ class CAS_Languages_English implements CAS_Languages_LanguageInterface
|
||||
{
|
||||
return 'The service `<b>%s</b>\' is not available (<b>%s</b>).';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/French.php
|
||||
* @category Authentication
|
||||
@@ -113,4 +113,4 @@ class CAS_Languages_French implements CAS_Languages_LanguageInterface
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
117
datamodels/2.x/authent-cas/vendor/apereo/phpcas/source/CAS/Languages/Galego.php
vendored
Normal file
117
datamodels/2.x/authent-cas/vendor/apereo/phpcas/source/CAS/Languages/Galego.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Galego.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Enrique Huelva Rivero enrique.huelvarivero@plexus.es
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Galego language class
|
||||
*
|
||||
* @class CAS_Languages_Galego
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Enrique Huelva Rivero enrique.huelvarivero@plexus.es
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*
|
||||
|
||||
* @sa @link internalLang Internationalization @endlink
|
||||
* @ingroup internalLang
|
||||
*/
|
||||
class CAS_Languages_Galego implements CAS_Languages_LanguageInterface
|
||||
{
|
||||
/**
|
||||
* Get the using server string
|
||||
*
|
||||
* @return string using server
|
||||
*/
|
||||
public function getUsingServer()
|
||||
{
|
||||
return 'usando servidor';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication wanted string
|
||||
*
|
||||
* @return string authentication wanted
|
||||
*/
|
||||
public function getAuthenticationWanted()
|
||||
{
|
||||
return 'Autenticación CAS necesaria!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logout string
|
||||
*
|
||||
* @return string logout
|
||||
*/
|
||||
public function getLogout()
|
||||
{
|
||||
return 'Saída CAS necesaria!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the should have been redirected string
|
||||
*
|
||||
* @return string should habe been redirected
|
||||
*/
|
||||
public function getShouldHaveBeenRedirected()
|
||||
{
|
||||
return 'Xa debería ser redireccionado ao servidor CAS. Faga click <a href="%s">aquí</a> para continuar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication failed string
|
||||
*
|
||||
* @return string authentication failed
|
||||
*/
|
||||
public function getAuthenticationFailed()
|
||||
{
|
||||
return 'Autenticación CAS errada!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the your were not authenticated string
|
||||
*
|
||||
* @return string not authenticated
|
||||
*/
|
||||
public function getYouWereNotAuthenticated()
|
||||
{
|
||||
return '
|
||||
<p>Non estás autenticado</p><p>Podes volver tentalo facendo click <a href="%s">aquí</a>.</p><p>Se o problema persiste debería contactar con el <a href="mailto:%s">administrador deste sitio</a>.</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service unavailable string
|
||||
*
|
||||
* @return string service unavailable
|
||||
*/
|
||||
public function getServiceUnavailable()
|
||||
{
|
||||
return 'O servizo `<b>%s</b>\' non está dispoñible (<b>%s</b>).';
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/German.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Greek.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Japanese.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/LanguageInterface.php
|
||||
* @category Authentication
|
||||
@@ -93,4 +93,4 @@ interface CAS_Languages_LanguageInterface
|
||||
public function getServiceUnavailable();
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
114
datamodels/2.x/authent-cas/vendor/apereo/phpcas/source/CAS/Languages/Portuguese.php
vendored
Normal file
114
datamodels/2.x/authent-cas/vendor/apereo/phpcas/source/CAS/Languages/Portuguese.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Portuguese.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Sherwin Harris <sherwin.harris@gmail.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Portuguese language class
|
||||
*
|
||||
* @class CAS_Languages_Portuguese
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Sherwin Harris <sherwin.harris@gmail.com>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS
|
||||
*
|
||||
* @sa @link internalLang Internationalization @endlink
|
||||
* @ingroup internalLang
|
||||
*/
|
||||
class CAS_Languages_Portuguese implements CAS_Languages_LanguageInterface
|
||||
{
|
||||
/**
|
||||
* Get the using server string
|
||||
*
|
||||
* @return string using server
|
||||
*/
|
||||
public function getUsingServer()
|
||||
{
|
||||
return 'Usando o servidor';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication wanted string
|
||||
*
|
||||
* @return string authentication wanted
|
||||
*/
|
||||
public function getAuthenticationWanted()
|
||||
{
|
||||
return 'A autenticação do servidor CAS desejado!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logout string
|
||||
*
|
||||
* @return string logout
|
||||
*/
|
||||
public function getLogout()
|
||||
{
|
||||
return 'Saida do servidor CAS desejado!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the should have been redirected string
|
||||
*
|
||||
* @return string should have been redirected
|
||||
*/
|
||||
public function getShouldHaveBeenRedirected()
|
||||
{
|
||||
return 'Você já deve ter sido redirecionado para o servidor CAS. Clique <a href="%s">aqui</a> para continuar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication failed string
|
||||
*
|
||||
* @return string authentication failed
|
||||
*/
|
||||
public function getAuthenticationFailed()
|
||||
{
|
||||
return 'A autenticação do servidor CAS falheu!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the your were not authenticated string
|
||||
*
|
||||
* @return string not authenticated
|
||||
*/
|
||||
public function getYouWereNotAuthenticated()
|
||||
{
|
||||
return '<p>Você não foi autenticado.</p><p>Você pode enviar sua solicitação novamente clicando <a href="%s">aqui</a>. </p><p>Se o problema persistir, você pode entrar em contato com <a href="mailto:%s">o administrador deste site</a>.</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service unavailable string
|
||||
*
|
||||
* @return string service unavailable
|
||||
*/
|
||||
public function getServiceUnavailable()
|
||||
{
|
||||
return 'O serviço `<b>%s</b>\' não está disponível (<b>%s</b>).';
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/Language/Spanish.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeAuthenticationCallException.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeClientException.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeProxyException.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/OutOfSequenceException.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/PGTStorage/AbstractStorage.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/PGTStorage/Db.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/PGTStorage/AbstractStorage.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/ProxiedService.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/ProxiedService/Abstract.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/ProxiedService/Exception.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/ProxiedService/Http.php
|
||||
* @category Authentication
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
* PHP Version 7
|
||||
*
|
||||
* @file CAS/ProxiedService/Http/Abstract.php
|
||||
* @category Authentication
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user