I switched the example to use requests because I don't have the Google App SDK installed but the below code works.
One important change was changing image to image[] to make so the remote end would recognize multiple inputs with the same name.  Not sure if the same would apply with urlfetch but I had  to add an extra \r\n after the raw post body.
For illustration and testing, I had it upload a second image.
First, the code:
from poster.encode import multipart_encode, MultipartParam
import requests
from pprint import pprint
file_content = open('/home/me/Pictures/admin.jpg', 'rb').read()
file_content2 = open('/home/me/Pictures/ed.jpeg', 'rb').read()
url = 'http://localhost/test.php'
parms = {
    'method': 'uploadphoto',
    'version': '1.2.3',
    'format': 'json'
}
mp_parms = []
for name, value in parms.items():
    mp_parms.append(MultipartParam(name, value, filetype='text/plain'))
file_photo = MultipartParam('image[]', file_content, 'file.jpeg', 'image/jpg')
mp_parms.append(file_photo)
file_photo = MultipartParam('image[]', file_content2, 'test.jpeg', 'image/jpg')
mp_parms.append(file_photo)
parameters, headers = multipart_encode(mp_parms)
pprint(headers)
#response = urlfetch.Fetch(url, payload=''.join(parameters), headers=headers, method=urlfetch.POST, deadline=60)
r = requests.post(url, data=''.join(parameters) + "\r\n", headers=headers)
print r.text
The test.php script it posts to contains <?php var_dump($_POST, $_FILES, $_SERVER); and shows output like:
// The post data:
array(3) {
  ["version"]=>
  string(5) "1.2.3"
  ["method"]=>
  string(11) "uploadphoto"
  ["format"]=>
  string(4) "json"
}
// The uploaded files (both of them as expected):
array(1) {
  ["image"]=>
  array(5) {
    ["name"]=>
    array(2) {
      [0]=>
      string(9) "file.jpeg"
      [1]=>
      string(9) "test.jpeg"
    }
    ["type"]=>
    array(2) {
      [0]=>
      string(9) "image/jpg"
      [1]=>
      string(9) "image/jpg"
    }
    ["tmp_name"]=>
    array(2) {
      [0]=>
      string(14) "/tmp/phpnbpGGx"
      [1]=>
      string(14) "/tmp/php7TVcyL"
    }
    ["error"]=>
    array(2) {
      [0]=>
      int(0)
      [1]=>
      int(0)
    }
    ["size"]=>
    array(2) {
      [0]=>
      int(71066)
      [1]=>
      int(30450)
    }
  }
}
# some server vars:
["CONTENT_LENGTH"]=>
  string(6) "102186"
["CONTENT_TYPE"]=>
  string(62) "multipart/form-data; boundary=73772149e2ef4a5daf9b5eb18a5d73f5"
It produced the following POST as grabbed in Wireshark:
POST /test.php HTTP/1.1
Host: localhost
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.12.1
Content-Length: 102186
Content-Type: multipart/form-data; boundary=176473ffab3146b5bfffc6185ad9474a
--176473ffab3146b5bfffc6185ad9474a
Content-Disposition: form-data; name="version"
Content-Type: text/plain
1.2.3
--176473ffab3146b5bfffc6185ad9474a
Content-Disposition: form-data; name="method"
Content-Type: text/plain
uploadphoto
--176473ffab3146b5bfffc6185ad9474a
Content-Disposition: form-data; name="format"
Content-Type: text/plain
json
--176473ffab3146b5bfffc6185ad9474a
Content-Disposition: form-data; name="image[]"; filename="file.jpeg"
Content-Type: image/jpg
......JFIF.....H.H.....C...................................
...snip...
..K5{......1....fh........k..n...
--176473ffab3146b5bfffc6185ad9474a
Content-Disposition: form-data; name="image[]"; filename="test.jpeg"
Content-Type: image/jpg
......JFIF.............;CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 90
...snip...
6.......~.h.j......}29..b~.h.).2.!E..tU.........L....d...lv..+....f)Y...
--176473ffab3146b5bfffc6185ad9474a--
HTTP/1.1 200 OK
I hope that helps.  I'm not sure if the API will care, but you might want to base64 encode the image data and set the Content-Encoding to base64 to keep raw binary out of the post.
If you're still stuck after integrating some of the changes let me know!