Checken inhoud document (Word)
Deze worden getoond via een embedded google docs.
Nu wil ik vooraf automatisch de inhoud van de tekst controleten op bijv. verboden linkjes.
Kan dit in PHP?
Je pakt het document dat naar de server is gestuurd uit (http://nl1.php.net/manual/en/book.zip.php) naar een map, daarin vind je het bestand word/document.xml en dat laad je in (http://nl1.php.net/manual/en/class.domdocument.php). Als je het DOMDocument-object platslaat als string, dan heb je in 1x de platte tekst.
Linkjes gaat ietsje ingewikkelder, maar dat moet je erg eenvoudig kunnen terugvinden in de XML. Het formaat is beter bekend als WordML.
Ik had ook al twee scripts gevonden in die richting.
Als ze samen willen werken laat ik het wel weten..
Ook met PDF bestanden gekeken.
Maar ze komen allemaal met een zuivere tekststring zonder linkjes.
Er is wel een mogelijkheid om bijv. afbeeldingen eruit te vissen.
Voor zover mij bekend staan de gegevens over de linkjes ook niet in de XML.
Ik hoef alleen maar te weten of er linkje(s) worden gebruikt.
Dan accepteer ik het document niet.
Maar nog niet gevonden dus.
Wel een script om binnen een string te kijken of er een link in zit.
Tips Blijven welkom!
Toevoeging op 07/04/2016 19:53:22:
Ik heb tot nu toe vanuit WORD een PDF bestand gemaakt.
Het maakt blijkbaar uit of ik echt iets als link schrijf (www.pctraverse.nl)
Of dat ik iets schrijf als mijn naam (Hans) en er dan een link van maak.
Zet ik dat om naar PDF dan wordt er een string van gemaakt.
Maar alleen de uitgeschreven link wordt geteld.
De andere wordt in de string gewoon gezien als naam (Hans).
Beetje denkwerk verrichten.
Toevoeging op 07/04/2016 20:32:24:
Zelfde doet zich voor als ik gewoon een DOCX bestand opslaat op de manier zoals aangegeven.
De echte linkjes worden netjes geteld, de bewerkte niet (Hans en dan een hyperlink er van maken)
Toevoeging op 07/04/2016 21:44:05:
Volgende script gebruik ik nu.
Ik heb even de XML bekeken van een bestand.
Ik moet niet zoeken in de string denk ik.
Maar op zoek gaan naar het woord "Hyperlink" in de XML.
Iemand een idee hoe ik in de XML kan kijken?
Het mag wel een string zijn maar dan moeten die gegevens neem
ik aan volledig worden weergegeven. Ander kom je het woord niet tegen.
Als ik het zip bestand open, dan zit het in de map "word".
En heet document.xml
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
function readZippedXML($archiveFile, $dataFile) {
// Create new ZIP archive
$zip = new ZipArchive;
// Open received archive file
if (true === $zip->open($archiveFile)) {
// If done, search for the data file in the archive
if (($index = $zip->locateName($dataFile)) !== false) {
// If found, read it to the string
$data = $zip->getFromIndex($index);
// Close archive file
$zip->close();
// Load XML from a string
// Skip errors and warnings
$xml = new DOMDocument();
$xml->loadXML($data, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
// Return data without XML formatting tags
return strip_tags($xml->saveXML());
}
$zip->close();
}
// In case of failure return empty string
return "";
}
$str = docx2text("test.docx"); // Save this contents to file
function makeLinks($str) {
$reg_exUrl = "/(((http|https|ftp|ftps)\:\/\/)|(www\.))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\:[0-9]+)?(\/\S*)?/";
$urls = array();
$urlsToReplace = array();
if(preg_match_all($reg_exUrl, $str, $urls)) {
$numOfMatches = count($urls[0]);
echo "aantal url ".$numOfMatches."<br>";
$numOfUrlsToReplace = 0;
for($i=0; $i<$numOfMatches; $i++) {
$alreadyAdded = false;
$numOfUrlsToReplace = count($urlsToReplace);
for($j=0; $j<$numOfUrlsToReplace; $j++) {
if($urlsToReplace[$j] == $urls[0][$i]) {
$alreadyAdded = true;
}
}
if(!$alreadyAdded) {
array_push($urlsToReplace, $urls[0][$i]);
}
}
$numOfUrlsToReplace = count($urlsToReplace);
for($i=0; $i<$numOfUrlsToReplace; $i++) {
$str = str_replace($urlsToReplace[$i], "<a href=\"".$urlsToReplace[$i]."\">".$urlsToReplace[$i]."</a> ", $str);
}
echo $str;
} else {
echo $str;
}
}
// Create new ZIP archive
$zip = new ZipArchive;
// Open received archive file
if (true === $zip->open($archiveFile)) {
// If done, search for the data file in the archive
if (($index = $zip->locateName($dataFile)) !== false) {
// If found, read it to the string
$data = $zip->getFromIndex($index);
// Close archive file
$zip->close();
// Load XML from a string
// Skip errors and warnings
$xml = new DOMDocument();
$xml->loadXML($data, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
// Return data without XML formatting tags
return strip_tags($xml->saveXML());
}
$zip->close();
}
// In case of failure return empty string
return "";
}
$str = docx2text("test.docx"); // Save this contents to file
function makeLinks($str) {
$reg_exUrl = "/(((http|https|ftp|ftps)\:\/\/)|(www\.))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\:[0-9]+)?(\/\S*)?/";
$urls = array();
$urlsToReplace = array();
if(preg_match_all($reg_exUrl, $str, $urls)) {
$numOfMatches = count($urls[0]);
echo "aantal url ".$numOfMatches."<br>";
$numOfUrlsToReplace = 0;
for($i=0; $i<$numOfMatches; $i++) {
$alreadyAdded = false;
$numOfUrlsToReplace = count($urlsToReplace);
for($j=0; $j<$numOfUrlsToReplace; $j++) {
if($urlsToReplace[$j] == $urls[0][$i]) {
$alreadyAdded = true;
}
}
if(!$alreadyAdded) {
array_push($urlsToReplace, $urls[0][$i]);
}
}
$numOfUrlsToReplace = count($urlsToReplace);
for($i=0; $i<$numOfUrlsToReplace; $i++) {
$str = str_replace($urlsToReplace[$i], "<a href=\"".$urlsToReplace[$i]."\">".$urlsToReplace[$i]."</a> ", $str);
}
echo $str;
} else {
echo $str;
}
}
Na
heb ik de rest niet echt nodig meer.
Gewijzigd op 07/04/2016 22:25:38 door Hans De Ridder
https://msdn.microsoft.com/en-us/library/ms406049.aspx#office2007WordFileFormat
Het bestandsformaat is Open XML, links heten kennelijk hyperlinks en worden opgeslagen als een bepaald type relationship in een map "_rels" of bestand met een ".rels" -extentie.
Om te weten of er links worden gebruikt moet je kijken of er in die verzameling(en) met relationships één of meer voorkomens zijn van:
Code (php)
1
<Relationship Id="someID" Type="http://schemas.microsoft.com/office/2006/relationships/hyperlink" Target="targetPart"/>
En dan weet je in als er bijvoorbeeld in de document.xml een referentie voorkomt, naar welke URL (targetPart?) die verwijst.
Disclaimer: ik vat nu de inhoud van de MSDN samen, maar ik heb het nog niet zelf uitgeprobeerd. Uiteraard ben ik benieuwd hoe het wil lukken.
Toevoeging op 07/04/2016 22:18:11:
Owh, en XML inlezen na het uitpakken kan idd. het beste met DOMDocument, en vervolgens met XPath-queries. De manual en usercomments moeten je in de goede weg wijzen, en als je het snel wilt snappen is er altijd nog het onvolprezen W3schools.com
Ik heb de docx uitgepakt met Winrar.
Had inderdaad gelezen dat in die map '_rel' wat moest staan.
Ik kom alleen iets specifieks tegen in het document.XML.
Wil ik die hyperlinks traceren (ook die niet volledig uitgeschreven zijn)
dan kan ik dat doen als ik dat XML bestand compleet als string kan weergeven.
In het script is daar ook aan voldaan.
Maar er worden daarna functies gebruikt om dat weer eruit te filteren.
Er moet ergens een functie zijn waarmee ik die XML kan uitlezen voordat die filtering optreedt.
Helaas nog niet gevonden...
Dit is een stukje uit de XML
Je ziet dan ook dat er hyperlinken bestaan van een echte URL, maar ook van het woord waar een hyperlink van is gemaakt.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- <w:r w:rsidRPr="00064D41">
- <w:rPr>
<w:rStyle w:val="Hyperlink" />
</w:rPr>
<w:t>Hans de Ridder</w:t>
</w:r>
</w:hyperlink>
</w:p>
- <w:p w:rsidR="00064D41" w:rsidRDefault="00064D41">
- <w:r>
<w:t>Verder gaat het wel</w:t>
</w:r>
</w:p>
- <w:p w:rsidR="004C2D21" w:rsidRDefault="004C2D21">
- <w:hyperlink r:id="rId5" w:history="1">
- <w:r w:rsidRPr="00761600">
- <w:rPr>
<w:rStyle w:val="Hyperlink" />
</w:rPr>
<w:t>www.pctraverse.nl</w:t>
</w:r>
</w:hyperlink>
- <w:rPr>
<w:rStyle w:val="Hyperlink" />
</w:rPr>
<w:t>Hans de Ridder</w:t>
</w:r>
</w:hyperlink>
</w:p>
- <w:p w:rsidR="00064D41" w:rsidRDefault="00064D41">
- <w:r>
<w:t>Verder gaat het wel</w:t>
</w:r>
</w:p>
- <w:p w:rsidR="004C2D21" w:rsidRDefault="004C2D21">
- <w:hyperlink r:id="rId5" w:history="1">
- <w:r w:rsidRPr="00761600">
- <w:rPr>
<w:rStyle w:val="Hyperlink" />
</w:rPr>
<w:t>www.pctraverse.nl</w:t>
</w:r>
</w:hyperlink>
Gewijzigd op 07/04/2016 22:38:01 door Hans De Ridder
Quote:
Ik geef leden van mijn website de mogelijkheid een soort nieuwsbrief in te sturen in Word.
Maar waarom in Word? Wat is er mis met HTML in een nieuwsbrief?
@Thomas zie je ooit mensen een HTML document aanleveren als kopij?
Even serieus nu: Waarom vraag je niet gewoon om platte tekst als kopij? Dat maakt je leven een stuk makkelijker (een link is zo herkend). Maar zoals je zelf al ziet bevat de XML de volledige informatie die je nodig hebt, en zelfs dan nog een stukje. Maar als je alleen wilt automatiseren dat een document wordt afgewezen op basis van het wel of niet aanwezig zijn van een link zou ik dit gewoon lekker laten voor wat het is. Kopij is meer dan het wel of niet aanwezig zijn van een link, en bij het doorlezen kom je deze snel genoeg tegen. Je hebt ongetwijfeld meer regels, zoals geen spam over een eigen bedrijf, niet haatdragend etc. Dit voelt dan een beetje als een zinloze controle.
Code (php)
1
2
2
$xml = new DOMDocument();
$xml->loadXML($data, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
$xml->loadXML($data, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
Vanaf dat moment heb je in de variabele $xml een pointer naar een instantie van het DOMDocument-object, waarmee je de XML-boom kan uitlezen en aanpassen, op het niveau van de structuur zelf, met nodes, attributen, etc.
Het enige dat je dan nog nodig hebt is een zoekfunctie om snel alle nodes op een rij te krijgen zodat je er doorheen kunt gaan met bv. een foreach-lus. Daar heb je XPath bij nodig.
http://php.net/manual/en/class.domdocument.php
http://php.net/manual/en/class.domxpath.php
De tweede link bevat een codevoorbeeld. XPath is een query-taal die je dan ook moet beheersen. Een introductie vind je hier: http://www.w3schools.com/xsl/xpath_intro.asp
Probeer het eerst vooral zelf, mocht je er niet uitkomen dan horen we het wel :-)
Misschien is 'nieuwsbrief' ook wel niet het juiste woord.
Want ga het script ook gebruiken bij rubrieken 'gestolen/vraag/aanbod.
Leden mogen een opgemaakt WORD bestand inleveren.
Maar omdat het een servicesite betreft voor artiesten, producenten, mensen van het geluid, etc.
moet ik ivm wetgeving een aantal zaken voorkomen.
Een van die dingen is het gebruik van linkjes voor uploads- en downloads van oa clouds.
Dus dat is wel een prioriteit.
Ik had wel wat scripts gevonden, maar die ontdekken uitsluitend de uitgeschreven linkjes als www.site.nl.
De woorden en zinnen binnen een word document waarvan een hyperlink is gemaakt, staan in string gewoon als naam of zin aangegeven.
Het zoeken moet dus worden gedaan in de XML file, waar daar komt als trefwoord 'hyperlink' voorbij, zowel voor de beschreven
linkjes als de gemaakte hyperlinks.
Had al wat zaken weggehaald en veranderd in die scripts. Maar verandere niet veel.
Overigens is het vinden van 1 'hyperlink' voldoende om af te keuren.
En optie daarbij is dan inderdaad dat je ook kunt filteren op schuttingtaal, enz.
Ik zal me er nog eens in verdiepen. Als het werkt horen jullie het wel weer.
Fijn weekend!
Toevoeging op 08/04/2016 23:08:33:
Hoe dom kun je zijn, haha...
De scripts werkten wel allemaal.
Alleen liet ik het resultaat telkens echoen in de browser.
Dan worden de codes niet zichtbaar, alleen de uitwerking uiteraard.
Toen ik uiteindelijk in de broncode keek veranderde wel degelijk iets.
Dus kan nu weer verder....
Gewijzigd op 08/04/2016 23:05:06 door Hans De Ridder
Bij het zoeken van schuttingtaal ben ik wel op een probleempje gestuit.
Door het wegfilteren van de XML tags is het aantal woorden wel afgenomen.
Maar ook het aantal spaties is oncontroleerbaar geworden. Woorden worden soms aan elkaar gebreid.
Er kan bijv. nu een string komen van:
Hans is een prutser, maar prutserzijnis ook niet altijd verkeerd.
Op zich niet zo'n probleem.
Maar nu moet ik dus voor het zoeken naar 'prutser' zowel zoeken naar een zelfstandig woord.
Maar ook binnen een substring van 'prutserzijnis'.
Uiteraard mag het niet uitmaken of er hoofdletters of kleine letters gebruikt worden.
Er kan nu ook onbedoeld schuttingtaal ontstaan, haha
Ik heb mijn buik vol Ulft.... Ik heb mijn buik volUlft....
Het aantal woorden baseer ik nu op de spatie tussen woorden.
Dus is in deze voorbeeldzin 10.
Is er een eenvoudige functie om dit te realiseren.
Gaat ook nog om meerdere woorden uiteraard om te zoeken.
Bedankt voor het meedenken.
Gewijzigd op 11/04/2016 14:00:25 door Hans De Ridder
Je geeft zelf ook al een voorbeeld van "false positives".
Overweeg moderatie, lijkt mij een stuk simpeler.
En als het een false positive geeft kan men de webbeheerder vragen.
Dan kan het document inderdaad door de webbeheerder alsnog geplaatst worden.
Zijn nooit documenten waar veel haast mee is.
Gewijzigd op 11/04/2016 14:38:46 door Hans De Ridder
Je kunt het ook omkeren: woorden whitelisten, omdat mensen ook gewoon k1ootzak (met cijfer 1 als kleine letter L) kunnen typen. Je kunt via http://www.opentaal.org beginnen met een basiswoordenlijst, en alleen woorden die niet bekend zijn er uit laten springen door het filter. Dan hoeft een moderator maar éénmalig veilige woorden toe te voegen via een "toestaan"- en "verbannen"-knop.
Denk dat ik in een tabel inderdaad de schuttingwoorden ga opslaan (en eventueel variaties). Dan kan ik via administratiepaneel woorden toevoegen.
Zal allemaal best mooier en beter uitgeschreven kunnen worden.
Dus kom gerust met veranderingen en verbeteringen.
Ik gebruik nu de XML string na enige filtering met tags om het woord "Hyperlink" te vinden.
Dat was nodig omdat WORD een gewone link (www.site.nl) anders interpreteert in XML dan een gemaakte link van een zin of woord.
Daarna gaan alle tags eruit.
En wordt de string gecontroleerd op scheldwoorden.
Komt er een link en/of scheldwoord voor dan kan het document niet geupload worden.
Zit een een verkeerde positief in, dan kan men contact opnemen met de webbeheerder.
Als je de complete XML bewaart, dan is het in principe mogelijk om woorden en linkjes te vervangen door bijv. "***". En daarna de omgekeerde weg te bewandelen om het weer terug in de zip te zetten.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?
$document = 'test.docx';
$c = strtolower(extracttext($document));
$d = woordfilter($c);
$e = linkfilter($d);
echo $e."<br>";
$f = strip_tags($c);
$h = scheldfilter($f);
echo $h;
function scheldfilter($f)
{
$schelden = array ('kat', 'hond', 'eend');
$sc = count($schelden);
$x = 0;
while ($x < $sc)
{
$sch = $schelden[$x];
$sche = strpos($f, $sch);
if ($sche >-1)
{
return "Scheldwoord(en) gevonden <br>";
}
$x ++;
}
}
function woordfilter($c)
{
$filter = array("openxmlformats", "<?xml version","</w:document>",
"http://schemas.microsoft.com/office/word/2006/wordml","http://schemas.openxmlformats.org/officeDocument/2006/");
$text = str_replace($filter,"", $c);
return $text;
}
function linkfilter($d)
{
if(strstr($d, 'hyperlink')){
return "Linkje(s) gevonden <br>";
}
else
{return "oke";}
}
/**Function to extract text*/
function extracttext($filename) {
//Check for extension
$ext = end(explode('.', $filename));
//if its docx file
if($ext == 'docx')
$dataFile = "word/document.xml";
//else it must be odt file
else
$dataFile = "content.xml";
echo $datafile;
//Create a new ZIP archive object
$zip = new ZipArchive;
// Open the archive file
if (true === $zip->open($filename)) {
// If successful, search for the data file in the archive
if (($index = $zip->locateName($dataFile)) !== false) {
// Index found! Now read it to a string
$text = $zip->getFromIndex($index);
// Load XML from a string
// Ignore errors and warnings
$xml = DOMDocument::loadXML($text, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
// Remove XML formatting tags and return the text
return $xml->saveXML();
//return $xml->saveXML();
}
//Close the archive file
$zip->close();
}
// In case of failure return a message
return "File not found";
}
?>
$document = 'test.docx';
$c = strtolower(extracttext($document));
$d = woordfilter($c);
$e = linkfilter($d);
echo $e."<br>";
$f = strip_tags($c);
$h = scheldfilter($f);
echo $h;
function scheldfilter($f)
{
$schelden = array ('kat', 'hond', 'eend');
$sc = count($schelden);
$x = 0;
while ($x < $sc)
{
$sch = $schelden[$x];
$sche = strpos($f, $sch);
if ($sche >-1)
{
return "Scheldwoord(en) gevonden <br>";
}
$x ++;
}
}
function woordfilter($c)
{
$filter = array("openxmlformats", "<?xml version","</w:document>",
"http://schemas.microsoft.com/office/word/2006/wordml","http://schemas.openxmlformats.org/officeDocument/2006/");
$text = str_replace($filter,"", $c);
return $text;
}
function linkfilter($d)
{
if(strstr($d, 'hyperlink')){
return "Linkje(s) gevonden <br>";
}
else
{return "oke";}
}
/**Function to extract text*/
function extracttext($filename) {
//Check for extension
$ext = end(explode('.', $filename));
//if its docx file
if($ext == 'docx')
$dataFile = "word/document.xml";
//else it must be odt file
else
$dataFile = "content.xml";
echo $datafile;
//Create a new ZIP archive object
$zip = new ZipArchive;
// Open the archive file
if (true === $zip->open($filename)) {
// If successful, search for the data file in the archive
if (($index = $zip->locateName($dataFile)) !== false) {
// Index found! Now read it to a string
$text = $zip->getFromIndex($index);
// Load XML from a string
// Ignore errors and warnings
$xml = DOMDocument::loadXML($text, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
// Remove XML formatting tags and return the text
return $xml->saveXML();
//return $xml->saveXML();
}
//Close the archive file
$zip->close();
}
// In case of failure return a message
return "File not found";
}
?>