How to read PHP output row by row and create HTML-links from each row - pdf

I'm having this PHP-script:
<?php
$old_path = getcwd();
chdir('/var/www/html/SEARCHTOOLS/');
$term1 = $_POST['query1'];
$term2 = $_POST['query2'];
$var = "{$term1} {$term2}";
$outcome = shell_exec("searcher $var");
chdir($old_path);
echo "<pre>$outcome</pre>";
?>
On a searchpage two searchwords are written and the searchbutton is pushed. The search result turns up as a webpage like this:
/var/www/html/SEARCHTOOLS/1974-1991.pdf:1
/var/www/html/SEARCHTOOLS/1974-1991.pdf:3
/var/www/html/SEARCHTOOLS/1974-1991.pdf:7
/var/www/html/SEARCHTOOLS/1974-1991.pdf:7
/var/www/html/SEARCHTOOLS/1974-1991.pdf:9
/var/www/html/SEARCHTOOLS/1974-1991.pdf:13
/var/www/html/SEARCHTOOLS/1974-1991.pdf:13
The result shows links to individual PDF-files and pagenumber in that file, but are not clickable.
Is there a way to make these links clickable so that it opens up for instance in Evince or Acrobat at the correct page number?
Many thanks in advance.
/Paul

I found a correct answer to my problem. It took some time, but here it is:
<?php
// Get current working directory and put it as variable
$old_path = getcwd();
// Change directory
chdir('/var/www/html/SEARCHTOOLS/');
// Create first variable as result of first searchword on searchpage
$term1 = $_POST['query1'];
// Create second variable as result of second searchword on searchpage
$term2 = $_POST['query2'];
// Create a variable combining first AND second variable
$var = "{$term1} {$term2}";
// Create a variable as the result of the executed search using command "sokare" and variable "$var"
$outcome = shell_exec("sokare $var");
// Return to starting directory
chdir($old_path);
// Split the varible "$outcome" per line representing every page in PDF-file where variable "$var" is found
foreach(preg_split("/((\r?\n)|(\r\n?))/", $outcome) as $line){
// Create a variable out of the given pagenumber in PDF-file
$end = substr($line, strpos($line, ":") + 1);
// Trim the line by removing leading directories from line
$line2 = str_replace('/var/www/html', '', $line);
// Change a string from lower to upper case
$line2 = str_replace('searchtools', 'SEARCHTOOLS', $line2);
// Remove the colon and anything behind it from line
$line2 = array_shift(explode(':', $line2));
// Add suffix to line to facilitate linking to pagenumber in PDF-file
$line3 = str_replace(" ", "_", $line2).'#page=';
// Add pagenumber from the variable "$end"
$line3 = str_replace(" ", "_", $line3).$end;
// Print each line as a correct URL-link
echo "<pre><a href=$line3>$line3</a></pre>";
}
?>
The search results will now turn up as (and are clickable):
/SEARCHTOOLS/1974-1991.pdf#page=1
/SEARCHTOOLS/1974-1991.pdf#page=3
/SEARCHTOOLS/1974-1991.pdf#page=7
Just a small edit. The line ....
// Add suffix to line to facilitate linking to pagenumber in PDF-file
$line3 = str_replace(" ", "_", $line2).'#page=';
...works better with:
// Add suffix to line to facilitate linking to pagenumber in PDF-file
if (substr($line2, -3) == 'pdf') {
$line3 = $line2.'#page=';
}

Related

Photoshop action for changing text number and saving with variable

I have a lot of graphic buttons that I need to make. I have 2 layers
TEXT (This is going to be numbers 1-48 for instance)
White Button image
I'm not sure how to go about writing this action or if I need a script. I need to have the text layer start at 1 and follow this progression.
save file w1.png (this yields a png with a button labeled with a "1"
change text to 2
save file w2.png (this yields a png with a button labeled with a "2"
change text to 3
. . . .
ect. . .all the way to 48. So this would make 48 images automatically. Can this be done with "actions" or do I need to learn scripting?
Save
You'll need a script for this, but it's going to be a rather simple one
function main() {
//this just checks if you have a text layer selected
try {
var textLayer = activeDocument.activeLayer.textItem
} catch (e) {
alert("active layer isn't a text layer");
return
};
var loops = 48,
pngSaveOptions = new PNGSaveOptions(),
outputFolder = Folder.selectDialog('', Folder.desktop); //this will ask for an output folder
for (var i = 0; i < loops; i++) {
var myNum = i + 1;
textLayer.contents = myNum; //this will change layer contents to number only. if you need some text here, write it in quotes like textLayer.contents = "my text" + myNum;
activeDocument.saveAs(new File(outputFolder + "/w" + myNum + ".png"), pngSaveOptions, true, Extension.LOWERCASE);
}
}
app.activeDocument.suspendHistory("temp", "main()");

Behat (+ Mink) Check for some text followed by some text (in sibling elements)

The I should see... function is an essential feature of Behat but I regularly find myself wanting to write something like this in my scenarios:
Then I should see "Session ID" followed by "3"
Which is my humanly-parsable way of describing 2 pieces of text next to each other in the content. That is to say the first string is the content of any element and the second is the content of it's next immediate sibling.
This would be useful for checking label - value type layouts:
Or if I want to check header - cell value type layouts in tabulated data:
Or even definition title - definition.
Obviously I could add 'id' attributes to every element I want to test but in a complicated page where many parts of the content need testing this starts to feel like I am bloating the markup with single-use attributes.
To be able to use...
Then I should see "Session ID" followed by "3"
Add the following methods to your FeatureContext.php file:
/**
* #Then I should see :textA followed by :textB
*/
public function iShouldSeeFollowedBy($textA, $textB)
{
$content = $this->getSession()->getPage()->getContent();
// Get rid of stuff between script tags
$content = $this->removeContentBetweenTags('script', $content);
// ...and stuff between style tags
$content = $this->removeContentBetweenTags('style', $content);
$content = preg_replace('/<[^>]+>/', ' ',$content);
// Replace line breaks and tabs with a single space character
$content = preg_replace('/[\n\r\t]+/', ' ',$content);
$content = preg_replace('/ {2,}/', ' ',$content);
if (strpos($content,$textA) === false) {
throw new Exception(sprintf('"%s" was not found in the page', $textA));
}
$seeking = $textA . ' ' . $textB;
if (strpos($content,$textA . ' ' . $textB) === false) {
// Be helpful by finding the 10 characters that did follow $textA
preg_match('/' . $textA . ' [^ ]+/',$content,$matches);
throw new Exception(sprintf('"%s" was not found, found "%s" instead', $seeking, $matches[0]));
}
}
/**
* #param string $tagName - The name of the tag, eg. 'script', 'style'
* #param string $content
*
* #return string
*/
private function removeContentBetweenTags($tagName,$content)
{
$parts = explode('<' . $tagName, $content);
$keepers = [];
// We always want to keep the first part
$keepers[] = $parts[0];
foreach ($parts as $part) {
$subparts = explode('</' . $tagName . '>', $part);
if (count($subparts) > 1) {
$keepers[] = $subparts[1];
}
}
return implode('', $keepers);
}

Undefined merge field in google apps script

I have a Google Apps Script for a Google Spreadsheet based on a Google Form that clients fill out online. The script is triggered by OnFormSubmit and generates a pdf based on a Google Doc template and sends the pdf to me by email using MailApp.sendEmail.
This script has been working fine until recently. The script runs successfully but the pdf output is incorrect. It seems like fields that are left blank are now being ignored in the script and so my pdf output shows the value for the next non-blank field. Ugh!
Anybody know what's going on here?
Below is an example of my script:
var docTemplate = "1FZL4rVe0LLpvMtIsq_3-pwv5POllIsyYThjfemkbkfg";
var docName = "Travel Details";
function onFormSubmit(e) {
var last = e.values[1];
var first = e.values[2];
var order = e.values[3];
var date = e.values[4];
var gender = e.values[5];
var email = "example#gmail.com";
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+last + ', ' + first)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLast', last);
copyBody.replaceText('keyFirst', first);
copyBody.replaceText('keyOrder', order);
copyBody.replaceText('keyDate', date);
copyBody.replaceText('keyGender', gender);
copyDoc.saveAndClose();
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
MailApp.sendEmail(email, subject, "", {htmlBody: office_message, attachments: pdf,
noReply:true});
DocsList.getFileById(copyId).setTrashed(true);
}
Example of the problem: If client leaves date field blank on the form, the gender value in the resulting pdf is put where the date value should be and the value for gender on the pdf shows "undefined".
Any ideas out there?
You should validate the values of all your variables.
if (last === undefined) {
last = 'No Data!'; //re-assign a different value
};
So, you are changing the value of the variable last if it somehow got set to undefined. That way, hopefully the pdf would still show the field.
If there is some bug that just showed up recently, you should report it as a bug. If everything was working fine, and now it's broken, Google may have changed something.
There might be something wrong with your code. I don't know. Have you looked under the "View" menu and the "Execution Transcript" to see if there are any errors? You should also use Logger.log statements: Logger.log('The value of last is: ' + last); to print output to the log. Then you can check what is actually going on.
I am no great coder but I use this script all the time to send pdf's I have never received an undefined if a field was missing. Typically if something is missing, the keygender is replaced with a blank spot and there is no error. In a spreadsheet, typically this means the columns were changed. It used to be timestamp(0), last(1), first(2), order(3), date(4), gender(5) and now their in a different order.
Try the below code it works
//commons errors -
//Triggers are not set
//spaces after Form questions
//e.values dont work when fields are not mandatory and left blank
//e.namedValues dont work for sending emails use e.values[#]
//place holder keys in template dont match
//spelling errors
//Note expect undefined error when de-bugging as values are not defined until form completed and submitted - run first with a small test form as per below
// Get Template
//from Google Docs and name it
var docTemplate = " "; // *** replace with new templae ID if new Template created***
var docName = "Test Script"; //replace with document name
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from the form and set as variables
//var variablename = "static entry or form value"
//Note: var Variablename = e.namedValues["X"]; is taking the value from the spreadsheet by column name so update if spreadsheet or form questions change
//Additions to the form will be added to the end of the spreadsheet regardless of their position in the form
var Timestamp = e.namedValues["Timestamp"];
var full_name = e.namedValues["Name"];
var position = e.namedValues["Position"]
var contact_email = e.namedValues["Contact Email"];
var phone_number = e.namedValues["Telephone Number"];
// Get document template, copy it as a new doc with Name and email, and save the id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(full_name+' '+docName+' for ' +contact_email+' '+Timestamp)//Update or remove Variablename to create full doc Name
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the documents body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys <<namedValues>> in template
//copyBody.replaceText('<<X>>', Variablename); Variables from above
//***Update if template is changed***
copyBody.replaceText('<<Timestamp>>', Timestamp);
copyBody.replaceText('<<Name>>', full_name);
copyBody.replaceText('<<Position>>', position);
copyBody.replaceText('<<Contact Email>>', contact_email);
copyBody.replaceText('<<Telephone Number>>', phone_number);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
{
// Add the data fields to the message
var s = SpreadsheetApp.getActiveSheet();
var columns = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = " ";
// Only include form fields that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] && (e.namedValues[key] != "") ) {
message += key+ ' : '+ e.namedValues[key] + "<br>";
}
}}
// Attach PDF and send the email
//***Change the "To" email address when to form goes live***
var to = "youremail#gmail.com";
var senders_name = e.values[1]
var contact_email = e.values[3]
var subject = "Test";
var htmlbody = "text goes here"+
"<br> <br>"+message+
"<br> <br>Submitted By:"+
"<br> <br>"+full_name+
"<br>"+position+
"<br>"+contact_email+
"<br>"+phone_number+
"<br> <br>Generated by Hansmoleman for Compu-Global-Hyper-Mega-Net";
MailApp.sendEmail({
name: senders_name,
to: to,
cc: contact_email,
replyTo: contact_email,
subject: subject,
htmlBody: htmlbody,
attachments: pdf,
});
}

Adobe AIR NativeProcess fails with spaces in arguments?

I have a problem running the NativeProcess if I put spaces in the arguments
if (Capabilities.os.toLowerCase().indexOf("win") > -1)
{
fPath = "C:\\Windows\\System32\\cmd.exe";
args.push("/c");
args.push(scriptDir.resolvePath("helloworld.bat").nativePath);
}
file = new File(fPath);
var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
nativeProcessStartupInfo.executable = file;
args.push("blah");
nativeProcessStartupInfo.arguments = args;
process = new NativeProcess();
process.start(nativeProcessStartupInfo);
in the above code, if I use
args.push("blah") everything works fine
if I use
args.push("blah blah") the program breaks as if the file wasn't found.
Seems like I'm not the only one:
http://tech.groups.yahoo.com/group/flexcoders/message/159521
As one of the users their pointed out, it really seems like an awful limitation by a cutting edge SDK of 21st century. Even Alex Harui didn't have the answer there and he's known to workaround every Adobe bug:)
Any ideas?
I am using AIR 2.6 SDK in JavaScript like this, and it is working fine even for spaces.
please check your code with this one.
var file = air.File.applicationDirectory;
file = file.resolvePath("apps");
if (air.Capabilities.os.toLowerCase().indexOf("win") > -1)
{
file = file.resolvePath(appFile);
}
var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
nativeProcessStartupInfo.executable = file;
var args =new air.Vector["<String>"]();
for(i=0; i<arguments.length; i++)
args.push(arguments[i]);
nativeProcessStartupInfo.arguments = args;
process = new air.NativeProcess();
process.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.addEventListener(air.ProgressEvent.STANDARD_INPUT_PROGRESS, inputProgressListener);
process.start(nativeProcessStartupInfo);
To expand on this: The reason that this works (see post above):
var args =new air.Vector["<String>"]();
for(i=0; i<arguments.length; i++)
args.push(arguments[i]);
nativeProcessStartupInfo.arguments = args;
is that air expects that the arguments being passed to the nativeProcess are delimited by spaces. It chokes if you pass "C:\folder with spaces\myfile.doc" (and BTW for AIR a file path for windows needs to be "C:\\folder with spaces\\myfile.doc") you would need to do this:
args.push("C:\\folder");
args.push("with");
args.push("spaces\\myfile.doc");
Hence, something like this works:
var processArgs = new air.Vector["<String>"]();
var path = "C:\\folder with spaces\\myfile.doc"
var args = path.split(" ")
for (var i=0; i<args.length; i++) {
processArgs.push(args[i]);
};
UPDATE - SOLUTION
The string generated by the File object by either nativePath or resolvePath uses "\" for the path. Replace "\" with "/" and it works.
I'm having the same problem trying to call 7za.exe using NativeProcess. If you try to access various windows directories the whole thing fails horribly. Even trying to run command.exe and calling a batch file fails because you still have to try to pass a path with spaces through "arguments" on the NativeProcessStartupInfo object.
I've spent the better part of a day trying to get this to work and it will not work. Whatever happens to spaces in "arguments" totally destroys the path.
Example 7za.exe from command line:
7za.exe a MyZip.7z "D:\docs\My Games\Some Game Title\Maps\The Map.map"
This works fine. Now try that with Native Process in AIR. The AIR arguments sanitizer is FUBAR.
I have tried countless ways to put in arguments and it just fails. Interesting I can get it to spit out a zip file but with no content in the zip. I figure this is due to the first argument set finally working but then failing for the path argument.
For example:
processArgs[0] = 'a';
processArgs[1] = 'D:\apps\flash builder 4.5\project1\bin-debug\MyZip.7z';
processArgs[2] = 'D:\docs\My Games\Some Game Title\Maps\The Map.map';
For some reason this spits out a zip file named: bin-debugMyZip.7z But the zip is empty.
Whatever AIR is doing it is fraking up path strings. I've tried adding quotes around those paths in various ways. Nothing works.
I thought I could fall back on calling a batch file from this example:
http://technodesk.wordpress.com/2010/04/15/air-2-0-native-process-batch-file/
But it fails as well because it still requires the path to be passed through arguments.
Anyone have any luck calling 7z or dealing with full paths in the NativeProcess? All these little happy tutorials don't deal with real windows folder structure.
Solution that works for me - set path_with_space as "nativeProcessStartupInfo.workingDirectory" property. See example below:
public function openPdf(pathToPdf:String):void
}
var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
var file:File = File.applicationDirectory.resolvePath("C:\\Windows\\System32\\cmd.exe");
nativeProcessStartupInfo.executable = file;
if (Capabilities.os.toLowerCase().indexOf("win") > -1)
{
nativeProcessStartupInfo.workingDirectory = File.applicationDirectory.resolvePath(pathToPdf).parent;
var processArgs:Vector.<String> = new Vector.<String>();
processArgs[0] = "/k";
processArgs[1] = "start";
processArgs[2] = "test.pdf";
nativeProcessStartupInfo.arguments = processArgs;
process = new NativeProcess();
process.start(nativeProcessStartupInfo);
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
}
args.push( '"blah blah"' );
Command line after all supports spaces if they are nested whithin "".
So if lets say you have a file argument :
'test/folder with space/blah'
Convert it to the following
'test/"folder with space"/blah'
Optionally use a filter:
I once had a problem like this in AIR, i just simply filter the text before i push it into the array. My refrence use CASA lib though
import org.casalib.util.ArrayUtil;
http://casalib.org/
/**
* Filters a string input for 'safe handling', and returns it
**/
public function stringFilter(inString:String, addPermitArr:Array = null, permitedArr:Array = null):String {
var sourceArr:Array = inString.split(''); //Splits the string input up
var outArr:Array = new Array();
if(permitedArr == null) {
permitedArr = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" as String).split('');
}
if( addPermitArr != null ) {
permitedArr = permitedArr.concat( addPermitArr );
}
for(var i:int = 0; i < sourceArr.length; i++) {
if( ArrayUtil.contains( permitedArr, sourceArr[i] ) != 0 ) { //it is allowed
outArr.push( sourceArr[i] );
}
}
return (outArr.join('') as String);
}
And just filter it via
args.push( stringFilter( 'blah blah', new Array('.') ) );
Besides, it is really bad practice to use spaces in file names / arguments, use '_' instead. This seems to be originating from linux though. (The question of spaces in file names)
This works for me on Windws7:
var Xargs:Array = String("/C#echo#a trully hacky way to do this :)#>#C:\\Users\\Benjo\\AppData\\Roaming\\com.eblagajna.eBlagajna.POS\\Local Store\\a.a").split("#");
var args:Vector.<String> = new Vector.<String>();
for (var i:int=0; i<Xargs.length; i++) {
trace("Pushing: "+Xargs[i]);
args.push(Xargs[i]);
};
NPI.arguments = args;
If your application path or parameter contains spaces, make sure to wrap it in quotes. For example path of the application has spaces C:\Program Files (x86)\Camera\Camera.exe use quotes like:
"C:\Program Files (x86)\Camera\Camera.exe"

How to convert file name with path to short file name (DOS style) in Adobe AIR?

How to convert file name with path to short file name (DOS style) in Adobe AIR?
For example convert next path
"C:\Program Files\Common Files\Adobe AIR\Versions\1.0\Resources\Adobe AIR Updater.exe"
to
"C:\PROGRA~1\COMMON~1\ADOBEA~1\VERSIONS\1.0\RESOUR~1\ADOBEA~1.EXE"
Is there any algorithm?
Assuming your text portion is a string variable, you can split it by using "\" as delimiter. Then, you will have an array which you can use to check if each block is longer than 8 characters. While looping the array you can chop the last characters of each long block and put ~1. Since you're in the loop, you can progressively add to a temporary variable all these changes which will give you the final edited result at the end.
The only part that's a bit tricky is to pay attention to .exe part at the end.
So, if I were you, I'd start reading on String.split(), String.substring(), for loop, arrays
Here's my handy method that does this below:
public static string GetShortPathName(string path)
{
string[] arrPath = path.Split(System.IO.Path.DirectorySeparatorChar);
path = arrPath[0]; // drive
// skip first, ( drive ) and last program name
for (int i = 1; i < arrPath.Length - 1; i++)
{
string dosDirName = arrPath[i];
if (dosDirName.Count() > 8)
{
dosDirName = dosDirName.Substring(0, 6) + "~1";
}
path += System.IO.Path.DirectorySeparatorChar + dosDirName;
}
// include program name if any
path += System.IO.Path.DirectorySeparatorChar + arrPath[arrPath.Length - 1];
return path;
}