Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
ee3eb8ac
Commit
ee3eb8ac
authored
Dec 04, 2017
by
Carsten Rose
Browse files
Feature 4255 / AttachmentsInEmail: Code ready for first test.
parent
bc8b6a04
Changes
9
Hide whitespace changes
Inline
Side-by-side
extension/qfq/api/download.php
View file @
ee3eb8ac
...
...
@@ -28,7 +28,7 @@ try {
$download
=
new
\
qfq\Download
();
// If all is fine - 'process()' never returns! The output file is delivered and PHP is stopped after that.
$data
=
$download
->
process
();
$data
=
$download
->
process
(
STORE_SIP
,
OUTPUT_MODE_DIRECT
);
}
catch
(
qfq\CodeException
$e
)
{
$data
=
$e
->
formatMessage
();
...
...
extension/qfq/qfq/Constants.php
View file @
ee3eb8ac
...
...
@@ -1102,8 +1102,6 @@ const SENDMAIL_TOKEN_DOWNLOAD_FILENAME = 'd';
const
SENDMAIL_TOKEN_ATTACHMENT_URL
=
'u'
;
const
SENDMAIL_TOKEN_ATTACHMENT_URL_LOCAL
=
'U'
;
const
SENDMAIL_PREFIX_TMP_ATTACHMENT
=
'/tmp/qfq.attachment/'
;
// Report, BodyText
const
TOKEN_SQL
=
'sql'
;
const
TOKEN_HEAD
=
'head'
;
...
...
@@ -1170,10 +1168,13 @@ const DOWNLOAD_MODE_PDF = 'pdf';
const
DOWNLOAD_MODE_EXCEL
=
'excel'
;
const
DOWNLOAD_MODE_ZIP
=
'zip'
;
const
DOWNLOAD_EXPORT_FILENAME
=
'_exportFilename'
;
const
DOWNLOAD
_FILE_PREFIX
=
'qfq.temp'
;
// temporary filename on server of single export file
const
TMP
_FILE_PREFIX
=
'qfq.temp'
;
// temporary filename on server of single export file
const
DOWNLOAD_OUTPUT_PDF
=
'output'
;
const
DOWNLOAD_SIP_ENCODE_PARAMETER
=
'_sip'
;
const
OUTPUT_MODE_DIRECT
=
'direct'
;
const
OUTPUT_MODE_FILE
=
'file'
;
// HTML2PDF
const
HTML2PDF_PAGEID
=
'id'
;
const
HTML2PDF_PARAM_GET
=
'paramGet'
;
...
...
@@ -1183,6 +1184,7 @@ const SESSION_COOKIE_PREFEIX = 'qfq.cookie.'; // temporary 'cookie file' to forw
// Class: LINK
const
PARAM_DELIMITER
=
'|'
;
const
PARAM_TOKEN_DELIMITER
=
':'
;
const
TOKEN_URL
=
'u'
;
const
TOKEN_MAIL
=
'm'
;
...
...
@@ -1202,7 +1204,6 @@ const TOKEN_HELP = 'H';
const
TOKEN_INFO
=
'I'
;
const
TOKEN_NEW
=
'N'
;
const
TOKEN_SHOW
=
'S'
;
const
TOKEN_SHOW
=
'S'
;
const
TOKEN_GLYPH
=
'G'
;
const
TOKEN_RENDER
=
'r'
;
const
TOKEN_TARGET
=
'g'
;
...
...
extension/qfq/qfq/helper/HelperFile.php
0 → 100644
View file @
ee3eb8ac
<?php
/**
* Created by PhpStorm.
* User: crose
* Date: 1/28/16
* Time: 8:05 AM
*/
namespace
qfq
;
require_once
(
__DIR__
.
'/../Constants.php'
);
class
HelperFile
{
/**
* Iterate over array $files. Delete only named files which are stored in '/tmp/' . DOWNLOAD_FILE_PREFIX.
*
* @param array $files
*/
public
static
function
cleanTempFiles
(
array
$files
)
{
foreach
(
$files
as
$file
)
{
if
(
self
::
isQfqTemp
(
$file
))
{
unlink
(
$file
);
}
$dir
=
dirname
(
$file
);
if
(
self
::
isQfqTemp
(
$dir
))
{
rmdir
(
$dir
);
}
}
}
/**
* Check against standard QFQ Temp location. If it is a Qfq Temp location, return true, else false.
*
* @param string $name Absolute filename.
*
* @return bool
*/
public
static
function
isQfqTemp
(
$name
)
{
$prefix
=
sys_get_temp_dir
()
.
'/'
.
TMP_FILE_PREFIX
;
$len
=
strlen
(
$prefix
);
return
(
substr
(
$name
,
0
,
$len
)
==
$prefix
);
}
/**
* Creates a temporary directory.
*/
public
static
function
mktempdir
()
{
$name
=
tempnam
(
sys_get_temp_dir
(),
TMP_FILE_PREFIX
);
unlink
(
$name
);
mkdir
(
$name
);
return
$name
;
}
}
\ No newline at end of file
extension/qfq/qfq/helper/Sanitize.php
View file @
ee3eb8ac
...
...
@@ -158,7 +158,7 @@ class Sanitize {
*
* @return mixed
*/
public
static
function
safeFilename
(
$filename
)
{
public
static
function
safeFilename
(
$filename
,
$flagBaseName
=
false
)
{
$search
=
array
(
// Definition of German Umlauts START
'/ß/'
,
...
...
@@ -177,6 +177,10 @@ class Sanitize {
'_'
,
);
if
(
$flagBaseName
)
{
$filename
=
basename
(
$filename
);
}
return
preg_replace
(
$search
,
$replace
,
$filename
);
}
// safeFilename()
...
...
extension/qfq/qfq/report/Download.php
View file @
ee3eb8ac
...
...
@@ -18,6 +18,7 @@ require_once(__DIR__ . '/../store/Store.php');
require_once
(
__DIR__
.
'/../helper/OnArray.php'
);
require_once
(
__DIR__
.
'/../helper/Logger.php'
);
require_once
(
__DIR__
.
'/../helper/Sanitize.php'
);
require_once
(
__DIR__
.
'/../helper/HelperFile.php'
);
require_once
(
__DIR__
.
'/../report/Html2Pdf.php'
);
//require_once(__DIR__ . '/Link.php');
//require_once(__DIR__ . '/Sendmail.php');
...
...
@@ -97,7 +98,8 @@ class Download {
break
;
}
$concatFile
=
tempnam
(
sys_get_temp_dir
(),
DOWNLOAD_FILE_PREFIX
);
$concatFile
=
tempnam
(
sys_get_temp_dir
(),
TMP_FILE_PREFIX
);
if
(
false
===
$concatFile
)
{
throw
new
DownloadException
(
'Error creating output file.'
,
ERROR_DOWNLOAD_CREATE_NEW_FILE
);
}
...
...
@@ -179,27 +181,6 @@ class Download {
print
file_get_contents
(
$file
);
}
/**
* Iterate over array $files. Delete all named files which exist in DOWNLOAD_TMP_DIR.
*
* @param array $files
*/
private
function
cleanTempFiles
(
array
$files
)
{
if
(
$this
->
downloadDebugLog
!=
''
)
{
return
;
}
$prefix
=
sys_get_temp_dir
()
.
'/'
.
DOWNLOAD_FILE_PREFIX
;
$len
=
strlen
(
$prefix
);
foreach
(
$files
as
$file
)
{
if
(
substr
(
$file
,
0
,
$len
)
==
$prefix
)
{
unlink
(
$file
);
}
}
}
/**
* Interprets $element and fetches corresponding content as file.
*
...
...
@@ -248,7 +229,7 @@ class Download {
*/
private
function
zipFiles
(
array
$files
)
{
$zipFile
=
tempnam
(
sys_get_temp_dir
(),
DOWNLOAD
_FILE_PREFIX
);
$zipFile
=
tempnam
(
sys_get_temp_dir
(),
TMP
_FILE_PREFIX
);
if
(
false
===
$zipFile
)
{
throw
new
DownloadException
(
"Error creating output file."
,
ERROR_DOWNLOAD_CREATE_NEW_FILE
);
}
...
...
@@ -259,12 +240,12 @@ class Download {
throw
new
DownloadException
(
"Error creating/opening new empty zip file:
$zipFile
"
,
ERROR_IO_OPEN
);
}
$len
=
strlen
(
DOWNLOAD
_FILE_PREFIX
);
$len
=
strlen
(
TMP
_FILE_PREFIX
);
$ii
=
1
;
foreach
(
$files
AS
$filename
)
{
$localname
=
substr
(
$filename
,
strrpos
(
$filename
,
'/'
)
+
1
);
if
(
substr
(
$localname
,
0
,
$len
)
==
DOWNLOAD
_FILE_PREFIX
)
{
if
(
substr
(
$localname
,
0
,
$len
)
==
TMP
_FILE_PREFIX
)
{
$localname
=
'file-'
.
$ii
;
$ii
++
;
}
...
...
@@ -284,13 +265,16 @@ class Download {
* <i>_id=<Typo3 pageId>
* <i>_<key>=<value i>
* Direct
* <i>_file=<filename>
*
<i>_file=<filename>
*
* @param array $vars [ DOWNLOAD_EXPORT_FILENAME, DOWNLOAD_MODE, SIP_DOWNLOAD_PARAMETER ]
*
* @param string $outputMode OUTPUT_MODE_DIRECT | OUTPUT_MODE_FILE
* @return string Filename of the generated file. The filename only points to a real existing filename with $outputMode=OUTPUT_MODE_FILE
* @throws CodeException
* @throws DownloadException
*/
private
function
doElements
(
array
$vars
)
{
private
function
doElements
(
array
$vars
,
$outputMode
)
{
$tmpFiles
=
array
();
...
...
@@ -333,24 +317,49 @@ class Download {
break
;
}
// Temporary files can be deleted.
if
(
$this
->
downloadDebugLog
==
''
)
{
HelperFile
::
cleanTempFiles
(
$tmpFiles
);
}
$exportFilename
=
empty
(
$vars
[
DOWNLOAD_EXPORT_FILENAME
])
?
DOWNLOAD_OUTPUT_PDF
:
$vars
[
DOWNLOAD_EXPORT_FILENAME
];
$this
->
outputFile
(
$filename
,
$exportFilename
);
switch
(
$outputMode
)
{
case
OUTPUT_MODE_FILE
:
break
;
case
OUTPUT_MODE_DIRECT
:
$this
->
outputFile
(
$filename
,
$exportFilename
);
HelperFile
::
cleanTempFiles
([
$filename
]);
break
;
$tmpFiles
[]
=
$filename
;
$this
->
cleanTempFiles
(
$tmpFiles
);
default
:
throw
new
CodeException
(
'Unkown mode: '
.
$outputMode
,
ERROR_UNKNOWN_MODE
);
}
return
$filename
;
}
/**
* Process download as requested in $vars. Output is either directly send to the browser, or a file which has to be deleted later.
*
* @param string|array $vars If $config is not an array, get values from STORE_SIP. If $config is an array, take it.
* @param string $outputMode OUTPUT_MODE_DIRECT | OUTPUT_MODE_FILE
*
* @return string
* @throws CodeException
* @throws DownloadException
* @throws UserFormException
*/
public
function
process
()
{
public
function
process
(
$vars
,
$outputMode
=
OUTPUT_MODE_DIRECT
)
{
$vars
=
$this
->
store
->
getStore
(
STORE_SIP
);
if
(
!
is_array
(
$vars
))
{
$vars
=
$this
->
store
->
getStore
(
STORE_SIP
);
}
$this
->
doElements
(
$vars
);
return
$this
->
doElements
(
$vars
,
$outputMode
);
}
}
...
...
extension/qfq/qfq/report/Html2Pdf.php
View file @
ee3eb8ac
...
...
@@ -206,7 +206,7 @@ class Html2Pdf {
$urlPrint
=
escapeshellarg
(
$url
);
$wkhtmlToPdf
=
$this
->
config
[
SYSTEM_WKHTMLTOPDF
];
$filename
=
tempnam
(
sys_get_temp_dir
(),
DOWNLOAD
_FILE_PREFIX
);
$filename
=
tempnam
(
sys_get_temp_dir
(),
TMP
_FILE_PREFIX
);
$filenameEscape
=
escapeshellarg
(
$filename
);
$cookieOptions
=
'--cookie-jar '
.
escapeshellarg
(
$this
->
sessionCookie
->
getFile
());
...
...
extension/qfq/qfq/report/Report.php
View file @
ee3eb8ac
...
...
@@ -1301,16 +1301,16 @@ class Report {
];
// Token based string? No: just explode and all is fine. This is the deprecated fixed position setup
if
(
!
isset
(
$data
[
1
])
||
$data
[
1
]
!=
':'
)
{
return
explode
(
'|'
,
$data
);
if
(
!
isset
(
$data
[
1
])
||
$data
[
1
]
!=
PARAM_TOKEN_DELIMITER
)
{
return
explode
(
PARAM_DELIMITER
,
$data
);
}
$segments
=
explode
(
'|'
,
$data
);
$segments
=
explode
(
PARAM_DELIMITER
,
$data
);
$arr
=
[
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
,
''
];
$attachmentCombineOpen
=
false
;
$attachment
=
array
();
foreach
(
$segments
AS
$line
)
{
$piece
=
explode
(
':'
,
$line
,
2
);
$piece
=
explode
(
PARAM_TOKEN_DELIMITER
,
$line
,
2
);
if
(
empty
(
$piece
[
0
]))
{
throw
new
UserReportException
(
"Missing token in sendmail"
,
ERROR_UNKNOWN_TOKEN
);
...
...
@@ -1334,7 +1334,9 @@ class Report {
case
SENDMAIL_TOKEN_ATTACHMENT_URL_LOCAL
:
case
SENDMAIL_TOKEN_DOWNLOAD_FILENAME
:
$val
=
empty
(
$piece
[
1
])
?
''
:
$piece
[
1
];
$attachment
[]
=
[
$piece
[
0
]
=>
$val
];
// $attachment[] = [$piece[0] => $val];
$attachment
[]
=
$piece
[
0
]
.
PARAM_TOKEN_DELIMITER
.
$val
;
break
;
default
:
...
...
extension/qfq/qfq/report/Sendmail.php
View file @
ee3eb8ac
...
...
@@ -7,6 +7,7 @@ namespace qfq;
require_once
(
__DIR__
.
'/../Constants.php'
);
require_once
(
__DIR__
.
'/../database/Database.php'
);
require_once
(
__DIR__
.
'/../store/Store.php'
);
require_once
(
__DIR__
.
'/../helper/Sanitize.php'
);
class
Sendmail
{
...
...
@@ -95,6 +96,7 @@ class Sendmail {
*/
private
function
sendEmail
(
array
$mailConfig
)
{
$args
=
array
();
$attachments
=
array
();
foreach
(
$mailConfig
as
$key
=>
$value
)
{
$mailConfig
[
$key
]
=
Support
::
escapeDoubleTick
(
$value
);
...
...
@@ -180,7 +182,7 @@ class Sendmail {
}
}
$this
->
attachmentsDelete
(
$attachments
);
HelperFile
::
cleanTempFiles
(
$attachments
);
}
/**
...
...
@@ -251,29 +253,44 @@ class Sendmail {
}
/**
* Removes all temporary created files.
*
* @param array $attachments
* @return array
*/
private
function
attachmentsDelete
(
array
$attachments
)
{
$len
=
strlen
(
SENDMAIL_PREFIX_TMP_ATTACHMENT
);
foreach
(
$attachments
as
$file
)
{
if
(
SENDMAIL_PREFIX_TMP_ATTACHMENT
==
substr
(
$file
,
0
,
$len
))
{
unlink
(
$file
);
$dir
=
dirname
(
$file
);
rmdir
(
$dir
);
}
}
}
private
function
attachmentsBuild
(
array
$attachments
)
{
$files
=
array
();
$download
=
new
Download
();
$tmpDir
=
sys_get_temp_dir
();
// Several attachments are possible. Process one by one.
foreach
(
$attachments
as
$attach
)
{
if
(
isset
(
$attach
[
0
]
&&
count
())
)
$files
[]
=
$vars
=
array
();
foreach
(
$attach
as
$element
)
{
$exportFilename
=
''
;
foreach
(
$element
as
$key
=>
$param
)
{
if
(
substr
(
$param
,
0
,
2
)
==
SENDMAIL_TOKEN_DOWNLOAD_FILENAME
.
PARAM_TOKEN_DELIMITER
)
{
$exportFilename
=
Sanitize
::
safeFilename
(
substr
(
$param
,
2
),
true
);
unset
(
$element
[
$key
]);
}
}
$vars
[
SIP_DOWNLOAD_PARAMETER
]
=
implode
(
PARAM_DELIMITER
,
$element
);
$vars
[
DOWNLOAD_MODE
]
=
DOWNLOAD_MODE_PDF
;
$file
=
$download
->
process
(
$vars
,
OUTPUT_MODE_FILE
);
if
(
!
empty
(
$exportFilename
))
{
$dir
=
HelperFile
::
mktempdir
();
if
(
HelperFile
::
isQfqTemp
(
$file
))
{
rename
(
$file
,
$exportFilename
);
$file
=
$exportFilename
;
}
}
$files
[]
=
$file
;
}
}
return
$files
;
}
}
extension/qfq/tests/phpunit/ReportTest.php
View file @
ee3eb8ac
...
...
@@ -1096,32 +1096,32 @@ EOF;
$this
->
assertEquals
(
$expect
,
$result
);
// Single attachment 'token based'
$attach
=
[[
[
'F
'
=>
'
fileadmin/test1.pdf'
]]
]
;
$attach
=
[[
'F
:
fileadmin/test1.pdf'
]];
$result
=
$this
->
report
->
sendmailConvertToken
(
't:john@doe.com|f:jane@miller.com|s:Latest|b:Dear John|F:fileadmin/test1.pdf'
);
$expect
=
[
'john@doe.com'
,
'jane@miller.com'
,
'Latest'
,
'Dear John'
,
''
,
''
,
''
,
''
,
''
,
''
,
$attach
,
''
,
''
,
''
,
''
,
''
,
''
];
$this
->
assertEquals
(
$expect
,
$result
);
// Three individual attachment 'token based'
// $attach = [ [ [ 'F' => 'fileadmin/test1.pdf' ], [ 'F' => 'fileadmin/test2.pdf' ], [ 'F' => 'fileadmin/test3.pdf' ] ] ] ;
$attach
=
[[
[
'F
'
=>
'
fileadmin/test1.pdf'
]
]
,
[
[
'F
'
=>
'
fileadmin/test2.pdf'
]
]
,
[
[
'F
'
=>
'
fileadmin/test3.pdf'
]]
]
;
$attach
=
[[
'F
:
fileadmin/test1.pdf'
],
[
'F
:
fileadmin/test2.pdf'
],
[
'F
:
fileadmin/test3.pdf'
]];
$result
=
$this
->
report
->
sendmailConvertToken
(
't:john@doe.com|f:jane@miller.com|s:Latest|b:Dear John|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf|F:fileadmin/test3.pdf'
);
$expect
=
[
'john@doe.com'
,
'jane@miller.com'
,
'Latest'
,
'Dear John'
,
''
,
''
,
''
,
''
,
''
,
''
,
$attach
,
''
,
''
,
''
,
''
,
''
,
''
];
$this
->
assertEquals
(
$expect
,
$result
);
// One individual attachment, one dual combined attachment
$attach
=
[[
[
'F
'
=>
'
fileadmin/test1.pdf'
]
]
,
[
[
'F
'
=>
'
fileadmin/test2.pdf'
]
,
[
'F
'
=>
'
fileadmin/test3.pdf'
]]
]
;
$attach
=
[[
'F
:
fileadmin/test1.pdf'
],
[
'F
:
fileadmin/test2.pdf'
,
'F
:
fileadmin/test3.pdf'
]];
$result
=
$this
->
report
->
sendmailConvertToken
(
't:john@doe.com|f:jane@miller.com|s:Latest|b:Dear John|F:fileadmin/test1.pdf|C|F:fileadmin/test2.pdf|F:fileadmin/test3.pdf'
);
$expect
=
[
'john@doe.com'
,
'jane@miller.com'
,
'Latest'
,
'Dear John'
,
''
,
''
,
''
,
''
,
''
,
''
,
$attach
,
''
,
''
,
''
,
''
,
''
,
''
];
$this
->
assertEquals
(
$expect
,
$result
);
// One individual attachment, one quad combined attachment
$attach
=
[[
[
'F
'
=>
'
fileadmin/test1.pdf'
]
]
,
[
[
'F
'
=>
'
fileadmin/test2.pdf'
]
,
[
'F
'
=>
'
fileadmin/test3.pdf'
]
,
[
'u
'
=>
'
http://nzz.ch'
]
,
[
'U
'
=>
'
export&a=100'
]]
]
;
$attach
=
[[
'F
:
fileadmin/test1.pdf'
],
[
'F
:
fileadmin/test2.pdf'
,
'F
:
fileadmin/test3.pdf'
,
'u
:
http://nzz.ch'
,
'U
:
export&a=100'
]];
$result
=
$this
->
report
->
sendmailConvertToken
(
't:john@doe.com|f:jane@miller.com|s:Latest|b:Dear John|F:fileadmin/test1.pdf|C|F:fileadmin/test2.pdf|F:fileadmin/test3.pdf|u:http://nzz.ch|U:export&a=100'
);
$expect
=
[
'john@doe.com'
,
'jane@miller.com'
,
'Latest'
,
'Dear John'
,
''
,
''
,
''
,
''
,
''
,
''
,
$attach
,
''
,
''
,
''
,
''
,
''
,
''
];
$this
->
assertEquals
(
$expect
,
$result
);
// Two quad combined attachment
e
$attach
=
[[
[
'd
-'
=>
'
output1.pdf'
]
,
[
'F
'
=>
'
fileadmin/test11.pdf'
]
,
[
'F
'
=>
'
fileadmin/test12.pdf'
]
,
[
'u
'
=>
'
http://nzz.ch.1'
]
,
[
'U
'
=>
'
export1&a=100'
]
]
,
[
[
'd
'
=>
'
output2.pdf'
]
,
[
'F
'
=>
'
fileadmin/test21.pdf'
]
,
[
'F
'
=>
'
fileadmin/test22.pdf'
]
,
[
'u
'
=>
'
http://nzz.ch.2'
]
,
[
'U
'
=>
'
export2&a=100'
]]
]
;
// Two quad combined attachment
s
$attach
=
[[
'd
:
output1.pdf'
,
'F
:
fileadmin/test11.pdf'
,
'F
:
fileadmin/test12.pdf'
,
'u
:
http://nzz.ch.1'
,
'U
:
export1&a=100'
],
[
'd
:
output2.pdf'
,
'F
:
fileadmin/test21.pdf'
,
'F
:
fileadmin/test22.pdf'
,
'u
:
http://nzz.ch.2'
,
'U
:
export2&a=100'
]];
$result
=
$this
->
report
->
sendmailConvertToken
(
't:john@doe.com|f:jane@miller.com|s:Latest|b:Dear John|C|d:output1.pdf|F:fileadmin/test11.pdf|F:fileadmin/test12.pdf|u:http://nzz.ch.1|U:export1&a=100|C|d:output2.pdf|F:fileadmin/test21.pdf|F:fileadmin/test22.pdf|u:http://nzz.ch.2|U:export2&a=100'
);
$expect
=
[
'john@doe.com'
,
'jane@miller.com'
,
'Latest'
,
'Dear John'
,
''
,
''
,
''
,
''
,
''
,
''
,
$attach
,
''
,
''
,
''
,
''
,
''
,
''
];
$this
->
assertEquals
(
$expect
,
$result
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment