I am writing a php program to write a binary file (may be video or image files). I would like to make it as a web service and call it from another application like c#, mac etc.
My code is give below,
<?php
$fileChunk = $_POST["filechunk"];
$vodFolder = 'D:\\HYSA SVN\\Trunk\\workproducts\\source\\hysa_he\\web\\entertainment\\';
$vodFile = $vodFolder . "abcd.mov";
$fh = fopen($vodFile, 'ab');
flock ($fh, LOCK_EX);
$varsize = fwrite($fh, $fileChunk);
fclose($fh);
?>
But when I called the php web service from a c# code, the abcd.mov is creating in the location, but its size is only one kb. I suspects that, the writing in halted when a character ‘&’ found in the binary file. I read the php documentation and found that, fopen with binary mode ‘b’ will solve this issue? But it is not working. Can somebody help me ?
This is my c# code.
BinaryReader b = new BinaryReader(File.Open("d:\\image38kb.jpg", FileMode.Open));
int pos = 0;
int length = (int)b.BaseStream.Length;
byte[] bt = b.ReadBytes(length);
char[] ch = b.ReadChars(length);
HttpWebRequest request = null;
Uri uri = new Uri("http://d0327/streamtest.php");
request = (HttpWebRequest)WebRequest.Create(uri);
NetworkCredential obj = new NetworkCredential("shihab.kb",
"India456*", "tvm");
request.Proxy.Credentials = obj;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = bt.Length;
using (Stream writeStream = request.GetRequestStream())
{
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes = encoding.GetBytes("filechunk=");
byte[] rv = new byte[bytes.Length + bt.Length];
System.Buffer.BlockCopy(bytes, 0, rv, 0, bytes.Length);
System.Buffer.BlockCopy(bt, 0, rv, bytes.Length, bt.Length);
writeStream.Write(rv, 0, bt.Length);
}
string result = string.Empty;
using (
HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8))
{
result = readStream.ReadToEnd();
}
}
}
Well the problem is not in the fwrite part, that works fine.
However, POST requests in HTTP look like this:
POST /somepage.php HTTP/1.1
Content-Length: 34
variable1=blah&var2=something else
As you can see, variables are divided by ampersands (&) (as well as equal signs (=) for the key - value mapping)... So, even when using POST requests, ampersands are not safe characters.
To solve this, you could try another transfer method, for example, TCP/IP socket connection, or simply escape the ampersands with, say '\x26' (the ASCII value of ampersand) and escape all the backslashes (\) with '\x5C'... You'd have to edit the PHP code to parse these values.
Related
I have a project I'm working on that uses an API for it request, but in order to preform them I need to generate the token first.
Before the API was update everything was working, after the update I don't know how to adjust my code to make it work again.
This was the code that worked before the update (Android | Kotlin):
fun hmacHash(str: String, secret: String): String {
val sha256HMAC = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
sha256HMAC.init(secretKey)
return convertToHex(sha256HMAC.doFinal(str.toByteArray()))
}
fun convertToHex(data: ByteArray): String {
val buf = StringBuilder()
for (b in data) {
var halfbyte = (b.toInt() shr 4) and (0x0F.toByte()).toInt()
var two_halfs = 0
do {
buf.append(if (halfbyte in 0..9) ('0'.toInt() + halfbyte).toChar() else ('a'.toInt() + (halfbyte - 10)).toChar())
halfbyte = (b and 0x0F).toInt()
} while (two_halfs++ < 1)
}
return buf.toString()
}
Which was equivalent to this PHP code:
hash_hmac('sha256', $string, $privateKey);
But now after the update the php code looks like this:
hash_hmac('sha256', $string, hex2bin($privateKey));
And I don't know how to adjust my code to make it work with this new change.
From what I can deduce, the PHP code made that change because $privateKey went from being plain text to being hex-encoded. So hex2bin was needed to change it back to plain text (hex2bin changes hex-encoded text to plain text; a confusingly named function if you ask me).
Since your secret is plain text, you don't need to change anything to match. But there are other ways to improve your code. For example, converting a byte array to a hex-encoded string is much easier than that.
fun hmacHash(str: String, secret: String): String {
val sha256HMAC = Mac.getInstance("HmacSHA256")
val bytes = secret.toByteArray()
val secretKey = SecretKeySpec(bytes, "HmacSHA256")
sha256HMAC.init(secretKey)
return convertToHex(sha256HMAC.doFinal(str.toByteArray()))
}
fun convertToHex(data: ByteArray): String =
data.joinToString("") { "%02x".format(it) }
I'm trying to send data from a VB.NET Application to a php application, i found this code:
Private Function SendRequest(uri As Uri, jsonDataBytes As Byte(),contentType As String, method As String) As String
Dim req As WebRequest = WebRequest.Create(uri)
req.ContentType = contentType
req.Method = method
req.ContentLength = jsonDataBytes.Length
Dim stream = req.GetRequestStream()
stream.Write(jsonDataBytes, 0, jsonDataBytes.Length)
stream.Close()
Dim response = req.GetResponse().GetResponseStream()
Dim reader As New StreamReader(response)
Dim res = reader.ReadToEnd()
reader.Close()
response.Close()
Return res
End Function
Dim data = Encoding.UTF8.GetBytes(jsonSring)
Dim result_post = SendRequest(uri, data, "application/json", "POST")
at: source
But I can't get the posted data on php. It sends the headers, but the data no.
So, I need help to figure it out what is missing.
I also had same issue and got solution from comments only. As you are passing binary data then in php you need to read binary data as raw input
To get the Raw Post Data:
<?php $postdata = file_get_contents("php://input"); ?>
Note: I am limited to PHP <-> VBA. Please do not suggest anything that requires an Excel Addon, or any other language/method.
I have a function that connect to a specified URL, submits data, and then retrieves other data. This works great. I'm trying to write it so i can use it as a generic function I can use to connect to any file I need to connect to - each would return different data (one could be user data, one could be complex calculations etc).
When it retrieves the data from PHP, is there a way to dynamically set the variables based on what is received - even if i do not know what has been received.
I can make PHP return to VBA the string in any format, so I'm using the below as an example:
String that is received in vba:
myValue1=Dave&someOtherValue=Hockey&HockeyDate=Yesterday
If i were to parse this in PHP, I could do something similar to (not accurate, just written for example purposes);
$myData = "myValue1=Dave&someOtherValue=Hockey&HockeyDate=Yesterday"
$myArr = explode("&",$myData)
foreach($myArr as $key => $value){
${$key} = $value;
}
echo $someOtherValue; //Would output to the screen 'Hockey';
I would like to do something similar in VBA. The string I am receiving is from a PHP file, so I can format it any way (json etc etc), I just essentially want to be able to define the VARIABLES when outputting the string from PHP. Is this possible in VBA?.
The current state of the function I have that is working great for connections is as below:-
Function kick_connect(url As String, formdata)
'On Error GoTo connectError
Dim http
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "POST", url, False
http.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
http.send (formdata)
kick_connect = http.responseText
Exit Function
connectError:
kick_connect = False
End Function
Ultimately, I want to be able to do something like
sub mySub
myData = "getId=" & Range("A1").Value
myValue = kick_connect("http://path-to-my-php-file.php",myData)
if myValue = False then
'Handle connection error here
exit sub
end if
'do something snazzy here to split "myValue" string (eg "myValue1=Dave&someOtherValue=Hockey&HockeyDate=Yesterday") into own variables
msgbox(myValue1) 'Should output "Dave"
end sub
Obviously I could put the values into an array, and reference that, however I specifically want to know if this exact thing is possible, to allow for flexibility with the scripts that already exist.
I hope this makes sense, and am really grateful for any replies i get.
Thank you.
You can use a Collection:
Dim Tmp As String
Dim s As String
Dim i As Integer
Dim colVariabili As New Collection
Tmp = "myValue1=Dave&someOtherValue=Hockey&HockeyDate=Yesterday"
Dim FieldStr() As String
Dim FieldSplitStr() As String
FieldStr = Split(Tmp, "&")
For Each xx In FieldStr
FieldSplitStr = Split(xx, "=")
colVariabili.Add FieldSplitStr(1), FieldSplitStr(0)
Next
Debug.Print colVariabili("myValue1")
Debug.Print colVariabili("someOtherValue")
Debug.Print colVariabili("HockeyDate")
It's ok if you don't have the correct sequence of var...
I am not sure if this can help you, but as far as I understand your question you want to be able to create the variables dynamically based on the query string parameters. If so then here is example how to add this variables dynamically. Code needs standard module with a name 'QueryStringVariables'. In this module the query string will be parsed and each query string parameter will be added as get-property. If you wish to be able to change the value as well then you will need to add let-property as well.
Add reference to Microsoft Visual Basic For Applications Extensibility
Option Explicit
Private Const SourceQueryString As String = "myValue1=Dave&someOtherValue=Hockey&HockeyDate=Yesterday"
Sub Test()
Dim queryStringVariablesComponent As VBIDE.vbComponent
Dim queryStringVariablesModule As VBIDE.CodeModule
Dim codeText As String
Dim lineNum As Long: lineNum = 1
Dim lineCount As Long
Set queryStringVariablesComponent = ThisWorkbook.VBProject.VBComponents("QueryStringVariables")
Set queryStringVariablesModule = queryStringVariablesComponent.CodeModule
queryStringVariablesModule.DeleteLines 1, queryStringVariablesModule.CountOfLines
Dim parts
parts = Split(SourceQueryString, "&")
Dim part, variableName, variableValue
For Each part In parts
variableName = Split(part, "=")(0)
variableValue = Split(part, "=")(1)
codeText = "Public Property Get " & variableName & "() As String"
queryStringVariablesModule.InsertLines lineNum, codeText
lineNum = lineNum + 1
codeText = variableName & " = """ & variableValue & ""
queryStringVariablesModule.InsertLines lineNum, codeText
lineNum = lineNum + 1
codeText = "End Property"
queryStringVariablesModule.InsertLines lineNum, codeText
lineNum = lineNum + 1
Next
DisplayIt
End Sub
Sub DisplayIt()
MsgBox myValue1 'Should output "Dave"
End Sub
Hoi!
I trying to make a webservice in Windows.
The client is Delphi 6, with MSXML2.XMLHTTP call, and other side is PHP.
First I tested: can I receive hungarian XML?
The PHP source was UTF-8 encoded file (PSPAD).
$s = 'alma árvíztűrő tükörfúrógép beta';
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;
$m = $doc->createElement('package');
$doc->appendChild($m);
$n = $doc->createElement('Msg');
$m->appendChild($n);
$n->nodeValue = $s;
$xs = $doc->saveXML();
header('Content-Type: text/xml');
echo($xs);
This package I fully got in Delphi side, the accents are ok.
So then I tried to inject data from xml (post xml to php with accents).
global $HTTP_RAW_POST_DATA;
$xmlstr = $HTTP_RAW_POST_DATA;
$xml = new SimpleXMLElement($xmlstr);
$msg = $xml->msg;
#$msg = 'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP';
Ok, I got the "msg" field, but nevertheless I trying to convert it, everytime I got some convert notice, and the result is not same as when I set the variable directly...
The debug is:
echo(utfCharToNumber($sinput).'<br>');
echo(utfCharToNumber($sdefined).'<br>');
Input: 195[ ]8286195141908419717682197[ ]328419
Defined: 195[129]8286195141908419717682197[144]328419
Input: 5156751951508270195154821951477119513780<br>
Defined: 5156751951508270195154821951477119513780<br>
As you see that two holes I have in the variable when I converted the input from MSXML2.
I really don't understand this.
I cannot reproduce same XML output from get the data from input XML as when I set directly in PHP code...
Why?
Thanks for your every help, idea, link, document, little example!
dd
Since you haven't included Delphi source, I suspect you're posting data straight from a string as content body of the request, which is encoded in the current ANSI encoding by default in Delphi 6. I advise you either use Utf8Encode on the string before you add this as the request's body data, or add a 'Content-encoding' request header with the name of the ANSI encoding (if I remember correctly GetLocaleInfo could give you this).
The source of the problem was the Delphi code.
Priorly I used AnsiToUTF8 to encode the XML text.
But the COM object is uses UTF16 as I think.
The working code is this:
procedure TForm1.Button4Click(Sender: TObject);
var
mhttp : variant;
ws : WideString;
tosend : OleVariant;
xml : TXMLDocument;
n : IXMLNode;
begin
mhttp := CreateOleObject('MSXML2.XMLHTTP');
mhttp.Open('POST', 'http://127.0.0.1/test_xmlgen.php', False);
xml := CreateANewDocument(Self, '', 'a');
n := xml.DocumentElement.AddChild('msg');
n.NodeValue := 'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP';
xml.SaveToXML(ws);
tosend := ws;
mhttp.send(tosend);
Memo1.Lines.Text :=
IntToStr(mhttp.Status) + #13 +
mhttp.responseText + #13;
end;
This can resend the XML I sent - with good accents.
Thanks for your help:
dd
I have a problem (server side) when i encrypt data from a client and i send to webserver with Post Method.
i Use this Method to Encrypt from a C# Client
public string Encrypt3DES(string strString)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = Encoding.GetBytes(this.Key);
DES.Mode = CipherMode.ECB;
DES.Padding = PaddingMode.Zeros;
ICryptoTransform DESEncrypt = DES.CreateEncryptor();
byte[] Buffer = encoding.GetBytes(strString);
return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}
When i send ecrypted String to PHP if there was a + in that string, php read it with a blank space. If instead there'isnt any '+' i haven't any problem.
For Example this is a Encrypted String 4aY+na42iaPg+aep== in C# when i read in php it's
4aY a42iaPg aep== so if i decrypt if dont match with the correct word.
i use this script to start read method post
if (isset($_POST['doConvalid'])){
if ($_POST['doConvalid']=='Convalid')
{
foreach($_POST as $keys => $values) {
$data[$keys] =($values); // post variables are filtered
}
$cheking=$data['check'];
echo("Show checking = $checking"); //Here i read string with blank space instead +
Is there a way to fix it?
Yes base64 decodes + to space use this:
echo str_replace(" ","+",$_POST['string']);
http://en.wikipedia.org/wiki/Base64#URL_applications
You could replace the '+' with a different character (something not used by base64) for sending. Then replace that character back to '+' for decoding.