<?php
$fo = fopen('php://output', 'w');
$fs = fopen('php://stdout', 'w');
fputs($fo, "You can see this with the CLI and Apache.\n");
fputs($fs, "This only shows up on the CLI...\n");
fclose($fo);
fclose($fs);
?>
When you're writing one line php scripts remember that 'php://stdin' is your friend. Here's a simple program I use to format PHP code for inclusion on my blog:
UNIX:
cat test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"
DOS/Windows:
type test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"
want a directory full of php files to be showns as source instead of being interpreted? don't want to rename every one from *.php to *.phps? then apache's forcetype directive is for you. drop this little baby into your .htaccess file and you'll be good to go.
<FilesMatch "\.(php)$">
ForceType application/x-httpd-php-source
</FilesMatch>
Microchip's 16F630 is a pretty cool little chip. One of its features is to interrupt when the input on a pin changes. I had a bit of a time figuring out how to do it so I'll put this up to save someone else the trouble.
The short version is: Enable interrupts with INTCON's GIE, PEIE and RAIE bits. Set bits in TRISA and IOCA that correspond to the pins to watch. In the interrupt handler read PORTA then clear INTCON's RAIF bit.
title "InputInterrupt" LIST P=16F630, F=INHX8M #include <p16f630.inc> __CONFIG _INTRC_OSC_NOCLKOUT & _CP_OFF & _MCLRE_OFF & _WDT_OFF XTAL EQU 4000000 ; internal crystal @ 4MHz ; backup spots for registers during interrupt handling w_bak equ 0x20 status_bak equ 0x21 fsr_bak equ 0x22 ; startup (at fixed address 0x0) org 0x0 goto Main ; interrupt handler (at fixed address 0x4) org 0x4 IntHandle ; save registers movwf w_bak swapf STATUS, W clrf STATUS movwf status_bak movfw FSR movwf fsr_bak ; jumpt to proper handler btfsc INTCON, RAIF ; check for port change goto PortHandler IntHandle_Return ; restore all the backed up registers movfw fsr_bak movwf FSR swapf status_bak, W movwf STATUS swapf w_bak, F swapf w_bak, W retfie ; return from interrupt PortHandler ; To clear the interrupt you have to do two things in order: ; * read the port ; * clear the interrupt flag ;DO STUFF HERE ; for testing copy inputs from port A to port C movfw PORTA movwf PORTC ; clear portchange interrupt flag bcf INTCON, RAIF goto IntHandle_Return ;End PortHandler Main ; enable interupts bsf INTCON, GIE ; enable global interrupts bsf INTCON, PEIE ; enable peripheral interrupts bsf INTCON, RAIE ; enable port change interrupts ; clear the port clrf PORTA ; make the changes to Bank 1 all at once bsf STATUS, RP0 ; Port A movlw B'00111111' ; all 6 pins will be inputs movwf TRISA ; set pin as input movwf IOCA ; interupt on change ; finished with Bank 1 bcf STATUS, RP0 MainLoop ; kill time here waiting for an interupt goto MainLoop end
after scouring the internet to find out how to do multipart post operations and finding nothing nothing, i decided to save someone else some time. the trick is that @ before the file name.
$fullflepath = 'C:\temp\test.jpg'; $upload_url = 'http://www.example.com/uploadtarget.php'; $params = array( 'photo'=>"@$fullfilepath", 'title'=>$title ); $ch = curl_init(); curl_setopt($ch, CURLOPT_VERBOSE, 1); curl_setopt($ch, CURLOPT_URL, $upload_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); $response = curl_exec($ch); curl_close($ch);
after my gallery albums got corrupted i started messing around with flickr and got hooked. i'd been pretty frustrated by gallery's rigid album structure, flickr's usage of tags and sets is much more to my liking. there's also an excellent api for those times when you need to roll your own app. the fact that they handle all the backup convinced me to throw down the $45 on a pro account.
now the task it to upload all of my photos to their servers. it's a good chance to go back and import all the old stuff that never made it into gallery. i'm starting with some albums i'd make using jason molenda's makethumbs shell script. i hacked together a perl script to parse the titles and descriptions from the description.txt file, upload the images, and add them to a set. click the read more link to view the script. i hope someone else may find it of use.
update: i finally got around to encoding it as valid html. copy and paste should work better.
#!/usr/bin/perl
use strict;
use warnings;
# upload a makethumbs album to flickr
#
# by andrew morton - http://drewish.com
#
# to use this script fill in the next three variables, then change
# to the directory with the makethumbs album and run it. email if
# you have problems.
my $flickr_email = 'your@email;
my $flickr_pass = 'secret';
my $photo_tags;
# shouldn't need to change anything below here.
# variables
my $flickr_key = '58ac590250ef4eeb81e6d853ee942034';
my @photo_ids; # id assigned after upload
my $config_file = 'descriptions.txt';
my $album_title; # album title
my $album_desc; # album description
my %image_title; # file titles
my %image_desc; # file descriptions
$|= 1; # auto flush
use Flickr::API;
use Flickr::API::Request;
use Flickr::Upload;
use LWP::UserAgent;
use XML::Parser::Lite::Tree::XPath;
ReadMakeThumbsData();
UploadToFlickr();
AddToNewSet();
print "All done.\n";
sub ReadMakeThumbsData() {
print "Loading makethumbs data from $config_file\n";
open(CONFIG, $config_file) or die "Can't open $config_file : $!\n";
# skip to short title section
while (<CONFIG>) {
last if /^\[short title\]/;
}
# suck up album title.
while (<CONFIG>) {
chomp;
last if /^\[longer page description\]/;
$album_title .= $_;
}
# suck up album description
while (<CONFIG>) {
chomp;
last if /^\[captions\]/;
$album_desc .= $_;
}
# suck up image titles
while (<CONFIG>) {
chomp;
next unless $_; # skip empty lines
last if /^\[descriptions\]/;
/^(\S*)\s(.*)/;
$image_title{$1} = $2;
}
# suck up image descriptions
while (<CONFIG>) {
chomp;
next unless $_; # skip empty lines
/^(\S*)\s(.*)/;
$image_desc{$1} = $2;
}
close CONFIG;
}
sub DebugPrintData() {
print("album title: $album_title\n");
print("album desc: $album_desc\n");
foreach my $key (keys %image_title) {
print "$key\n\ttitle: $image_title{$key}\n";
print "\tdesc: $image_desc{$key}\n";
}
}
sub UploadToFlickr() {
my $ua = LWP::UserAgent->new;
my $file;
my $id;
print "Uploading photos to flickr for $flickr_email\n";
foreach $file (sort(keys %image_title)) {
print "$file";
print "\n\ttitle: $image_title{$file}" if $image_title{$file};
print "\n\tdescription: $image_desc{$file}" if $image_desc{$file};
print "...";
$id = Flickr::Upload::upload(
$ua,
'email' => $flickr_email,
'password' => $flickr_pass,
'photo' => $file,
'title' => $image_title{$file},
'description' => $image_desc{$file},
# Everyone can view
'is_public' => 1,
'is_friend' => 1,
'is_family' => 1,
'tags' => $photo_tags
);
if ($id) {
push @photo_ids, $id;
print " assigned id $id\n";
} else {
print STDERR "Failed to upload $file";
}
}
}
sub AddToNewSet() {
my $api = new Flickr::API({'key' => $flickr_key});
my $response;
my $xpath;
my @nodes;
print "Creating set '$album_title' ...";
$response = $api->execute_method(
'flickr.photosets.create',
{
'email' => $flickr_email,
'password' => $flickr_pass,
'title' => $album_title,
'description' => $album_desc,
'primary_photo_id' => 3654245# $photo_ids[0]
}
);
$response->{success} or
die "Could not create the set : $response->{error_message} \n";
$xpath = new XML::Parser::Lite::Tree::XPath($response->{tree});
@nodes = $xpath->select_nodes('/photoset');
print " assigned id: $nodes[0]->{attributes}->{id}\n";
print "Adding photos to set...";
$response = $api->execute_method(
'flickr.photosets.editPhotos',
{
'email' => $flickr_email,
'password' => $flickr_pass,
'photoset_id' => $nodes[0]->{attributes}->{id},
'primary_photo_id' => $photo_ids[0],
'photo_ids' => join(', ', @photo_ids)
}
);
$response->{success} or
die "Could not add photos to set : $response->{error_message} \n";
print " finished.\n";
}
i've had to do this enough times that it seemed worth putting up on the blog to reference.
' take the values from the specified field in the specified
' table and concatinate them into a comma separated list.
Public Function ConcatColVals(source As String, field As String) As String
Dim ret As String
' open a recordset, enumerate the records and build a string
With New Recordset
.Open source, Application.CurrentProject.Connection, _
adOpenForwardOnly, adLockReadOnly
If Not .EOF Then
ret = .Fields(field).Value
.MoveNext
Do While Not .EOF
ret = ret & ", " & .Fields(field).Value
.MoveNext
Loop
End If
End With
' return the value
ConcatColVals = ret
End Function
for google's reference, if you ever need to register a satellite forms conduit from dot net use the palm cdk 4.03 and the following code:
' find out if the conduit is already registered
Public ReadOnly Property IsConduitRegistered() As Boolean
Get
Try
Dim CondMgr As New PDStandardLib.PDCondMgr
Dim ids() As Integer = CType(CondMgr.GetConduitList(), Integer())
If ids Is Nothing Then
Return False
Else
' sort sort it for the binary search
Array.Sort(ids)
' if the id exists in the array the conduit is registered
Return (0 < Array.BinarySearch(ids, PALM_CREATOR_INTEGER))
End If
Catch ex As Exception
Return False
End Try
End Get
End Property
' register the palm sync conduit
Public Sub RegisterConduit()
Try
Dim CondInfo As PDStandardLib.PDConduitInfo
' remove any old conduit registration
If Me.IsConduitRegistered Then
Me.UnregisterConduit()
End If
' Set the conduit entries
CondInfo = New PDStandardLib.PDConduitInfo
With CondInfo
.FileName = Environment.SystemDirectory & "\" & SF_SYNC_DLL
.CreatorID = PALM_CREATOR_INTEGER
.HandHeldDB = "SatFormsEE"
.DeskTopDataDirectory = "SatFormsEE"
.DeskTopDataFile = "SatFormsEE"
.DisplayName = "TecSync"
.Priority = 2
End With
With New PDStandardLib.PDCondMgr
' register it...
.RegisterConduit(CondInfo)
' refresh the list so it'll appear
With New PDStandardLib.PDHotSyncUtility
.RefreshConduitInfo()
End With
' ... and then test that we can retrieve it
CondInfo = CType(.GetConduitInfo(PALM_CREATOR_INTEGER), PDStandardLib.PDConduitInfo)
If CondInfo Is Nothing Then
Throw New ApplicationException("The conduit seemed to register correctly but could not be retrieved afterwards. ")
End If
End With
Catch ex As System.Runtime.InteropServices.COMException
Throw New ApplicationException("Could not register the TecSync Palm conduit. The ConduitManager had a problem. " & ex.Message)
Catch ex As ApplicationException
Throw New ApplicationException("Could not register the TecSync Palm conduit. " & ex.Message)
End Try
End Sub
' unregister the palm sync conduit
Public Sub UnregisterConduit()
Try
' unregister it
With New PDStandardLib.PDCondMgr
.UnregisterConduit(PALM_CREATOR_INTEGER)
End With
' then refresh the list so it'll disapear
With New PDStandardLib.PDHotSyncUtility
.RefreshConduitInfo()
End With
Catch ex As System.Runtime.InteropServices.COMException
Throw New ApplicationException("Coundn't unregister the TecSync Palm conduit. " & ex.Message)
End Try
End Sub