Schaken Posted March 6, 2023 Posted March 6, 2023 I am building a game, and in the game, users will be able to upload their screenshots to the community. I got it all working but everything I try I get 1 of 2 errors. The API returns Error "No_Image" or Error "EXO" (Unknown) In C# there is a very easy way to encode any byte date into a base64 Encoded format, so I dont think there is anything wrong with my code. Does anyone have any ideas on why im getting this issue? There is API for other sited that require filed in the same fashion, im using the same code I do this with them, and dont have issues until I use it on Invision. byte[] imageArray = System.IO.File.ReadAllBytes(FileDir); string base64ImageRepresentation = Convert.ToBase64String(imageArray); Dictionary<string, string> content = new Dictionary<string, string>(); content.Add("category", "27"); content.Add("image", base64ImageRepresentation); content.Add("author", "3"); content.Add("caption", ImageDescription.text); content.Add("filename", ImageDescription.text); content.Add("description", ImageTitle.text); UnityWebRequest www = UnityWebRequest.Post("https://xxxxxxxxxxxxx.com/api/gallery/images?key=xxxxxxxxxxxx551", content); yield return www.SendWebRequest(); if (www.result == UnityWebRequest.Result.ConnectionError) { Debug.Log("Error While Sending TEST: " + www.error); } else { string result = www.downloadHandler.text; string FullTXT = System.Text.RegularExpressions.Regex.Unescape(result); Debug.Log("Returned message: " + FullTXT); }
Stuart Silvester Posted March 6, 2023 Posted March 6, 2023 You might have to package your base64 string in a web-safe way, in PHP we do this similar to: rtrim( strtr( base64_encode( 'string' ), '+/', '-_' ), '=' ); It looks like you may be able to use something like this, but I'm not familiar with c# or unity. Convert.ToBase64String(imageArray).TrimEnd('=').Replace('+', '-').Replace('/', '_'); NO_IMAGE can mean that either no image was provided, the data provided couldn't be decoded to an image, or the magic bytes in the image do not match the expected values. I'm assuming that isn't your real API key, but you will want to change it if it is (I have also edited it).
Schaken Posted March 6, 2023 Author Posted March 6, 2023 I love how you take that extra step and even look up functions and convert and rewrite in a language you aren't familiar with, just to give a better customer service. I really appreciate you. I will work on this for a while and if I can't get this to work or any variant, I will let you know. IF I understand this right, I'm replacing all "+" signs with a "-" sign, replacing all "/" signs with a "_" sign, and trimming everything after the last "=" sign?
Schaken Posted March 7, 2023 Author Posted March 7, 2023 So far I am getting the same result. it is telling me "No Image". I have it set to Debug and show me the results and the Encoded is an insane number of numbers and letters, so i know it is doing something and appears right. Also, all the letters you have set to change did in fact change. Here is an update to the code. You can see the different things I tried. I changed it over to using OAuth2 instead of RestAPI, as most things usually work easier using OAuth2. public void UploadImage() { StartCoroutine(PostTopicPostsA()); } IEnumerator PostTopicPostsA() { byte[] imageArray = System.IO.File.ReadAllBytes(FileDir); string A = Convert.ToBase64String(imageArray);//.TrimEnd('=').Replace('+', '-').Replace('/', '_'); A = System.Text.RegularExpressions.Regex.Escape(A); Debug.Log("Image string: "+A); Debug.Log("Imape Path: "+FileDir); Dictionary<string, string> content = new Dictionary<string, string>(); content.Add("category", "27"); content.Add("image", A);//ImageString); content.Add("caption", ImageTitle.text); // Filename? content.Add("filename", ImageTitle.text); // Real title. content.Add("description", ImageDescription.text); // Description. UnityWebRequest www = UnityWebRequest.Post("https://schaken-mods.com/api/gallery/images", content); www.SetRequestHeader("Authorization", "Bearer " + OAH.BearerID); yield return www.SendWebRequest(); if (www.result == UnityWebRequest.Result.ConnectionError) { Debug.Log("Error While Sending TEST: " + www.error); } else { string result = www.downloadHandler.text; string FullTXT = System.Text.RegularExpressions.Regex.Unescape(result); Debug.Log("TEST: " + FullTXT); } } Result Debug Log: and it DOES upload... just its empty. I downloaded it and the file size was 0. This is just not making any sense to me why it is NOT working. This tells me every part of my code is working, except for the Base64 Encoded field. and obviously it is very close, otherwise it would tell me "No_Image"
IPCommerceFan Posted March 7, 2023 Posted March 7, 2023 (edited) I don't know C#, but I would try sending a text field for troubleshooting purposes instead of trying to get an image to work. If it sends over garbled text, then you may discover it is sending the text in the wrong encoding and can course-correct from there. I ran into this recently with a Selenum script, where I used javascripts btoa() function to base64 encode some text, but when I received it on the php side, it was a bunch of gobbledegook. In my case I had to say: base64_decode(urlencode($_GET['stuff'])); instead of what I previously had: $html = base64_decode($_GET['calidpanel']); urlencode did the job of "un-garbling" the text before base64 decoding it. For your case, Google led me to this result, which you may find useful: https://stackoverflow.com/questions/46093210/c-sharp-version-of-the-javascript-function-btoa Specifically: Quote Worked it out. For anyone wondering the encoding used is iso encoding. The btoa function in javascript can be replicated by using the following c# method: public string encoding(string toEncode) { byte[] bytes= Encoding.GetEncoding(28591).GetBytes(toEncode); string toReturn = System.Convert.ToBase64String(bytes); return toReturn; } Edited March 7, 2023 by IPCommerceFan
Schaken Posted March 7, 2023 Author Posted March 7, 2023 2 minutes ago, IPCommerceFan said: I don't know C#, but I would try sending a text field for troubleshooting purposes instead of trying to get an image to work. If it sends over garbled text, then you may discover it is sending the text in the wrong encoding and can course-correct from there. I ran into this recently with a Selenum script, where I used javascripts btoa() function to base64 encode some text, but when I received it on the php side, it was a bunch of gobbledegook. In my case I had to say: base64_decode(urlencode($_GET['stuff'])); instead of what I previously had: $html = base64_decode($_GET['calidpanel']); urlencode did the job of "un-garbling" the text before base64 decoding it. Google led me to this result, which you may find useful: https://stackoverflow.com/questions/46093210/c-sharp-version-of-the-javascript-function-btoa Specifically: I appreciate you jumping in. You are saying I should try to encode a text field as well and see how it turns out on the other side? Will it decode any text field on its own or is there a certain place I should send an encoded string to for testing? Your exact suggestion was why I tried using: A = System.Text.RegularExpressions.Regex.Escape(A); As this turns it into a URL friendly version. I will mess around with what you suggested with "Btoa" function, I never used it before but I will see if I can find a proper way to apply it and see if that helps. Again, thank you for your advice. I appreciate it. I just recently took on C# as the first programming language to learn, been at it for maybe 7 months. its alot to take in. IPCommerceFan 1
IPCommerceFan Posted March 7, 2023 Posted March 7, 2023 Yup I'm figuring maybe the initial encoding is defaulting to some format the REST API on the php side isn't interpreting correctly. Nice, I have a co-worker who keeps telling me I should learn C#, then F# since they're pretty much ubiquitous. I've thus far ignored him and continue on my merry way with in php/mysql-land. lol
Stuart Silvester Posted March 7, 2023 Posted March 7, 2023 An 'EX0' error code means that there was an uncaught exception. The system log in your AdminCP will have more information about it (including a back trace)
Schaken Posted March 7, 2023 Author Posted March 7, 2023 27 minutes ago, IPCommerceFan said: Yup I'm figuring maybe the initial encoding is defaulting to some format the REST API on the php side isn't interpreting correctly. Nice, I have a co-worker who keeps telling me I should learn C#, then F# since they're pretty much ubiquitous. I've thus far ignored him and continue on my merry way with in php/mysql-land. lol PHP is REALLY more useful from what I see. C# is centered more towards desktop apps, video games, handling your computer tasks. If you mainly only care to handle things on the internet browser world, then there isn't much of a reason to learn C#. I make video games and have an online website community, so I know a little bit of PHP (Very little) but im pretty fair with C#. The command you sent me is great, but I can only use it on text. but I see you are telling maybe it's how it is turning the image into a string that may be the issue, rather than how I am turning it into a base64 encode. This is something I didn't think about. I will tackle that area; you may very well be correct. @Stuart Silvester this is the error I am getting: The last thing there mentions Dimensions, so I went to my gallery settings and set the maximum to the same dimension of the image I was uploading, that didn't seem to make a difference. So, I'm not sure what the error is telling me, unless it is trying to get the dimensions, but can't because it's getting the image as a fumbled letters and numbers like @IPCommerceFan was suggesting. IPCommerceFan 1
Schaken Posted March 7, 2023 Author Posted March 7, 2023 Im at a loss. I spent a full day on this, scouring the internet for any ideas and trying mixes of all variants or every sort, I am starting to believe something is just broken between point A and B. Is there a way someone can test this even if it is in just PHP? even on their own server... I just need to know its not something broke. this has to work at some point, one of the variants I tried should work. here is what I have and with all the variants marked out as i would copy and paste back and forth with other ideas. IEnumerator PostTopicPostsA() { //byte[] imageArray = System.IO.File.ReadAllBytes(FileDir); string A = @"data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(FileDir)).TrimEnd('=').Replace('+', '-').Replace('/', '_');//Convert.ToBase64String(imageArray);//; //A = System.Text.RegularExpressions.Regex.Unescape(A); Debug.Log("Image string: "+A); Debug.Log("Imape Path: "+FileDir); Dictionary<string, string> content = new Dictionary<string, string>(); content.Add("category", "27"); content.Add("image", A);//ImageString); content.Add("caption", ImageTitle.text); // Filename? content.Add("filename", ImageTitle.text); // Real title. content.Add("description", ImageDescription.text); // Description. UnityWebRequest www = UnityWebRequest.Post("https://schaken-mods.com/api/gallery/images", content); www.SetRequestHeader("Authorization", "Bearer " + OAH.BearerID); yield return www.SendWebRequest(); if (www.result == UnityWebRequest.Result.ConnectionError) { Debug.Log("Error While Sending TEST: " + www.error); } else { string result = www.downloadHandler.text; string FullTXT = System.Text.RegularExpressions.Regex.Unescape(result); Debug.Log("TEST: " + FullTXT); } } I just keep getting "No image" and when i use the "@"data:image/png;base64," part, I get an EXO error same as the one I posted above.
Schaken Posted March 14, 2023 Author Posted March 14, 2023 I still have not got this to work. Can anyone verify that the uploading for API actually works? I want to verify it is not a bug in Invision.
Daniel F Posted March 14, 2023 Posted March 14, 2023 2 hours ago, Schaken said: Can anyone verify that the uploading for API actually works? I want to verify it is not a bug in Invision. Yes, it's working. Here's my php version of a quick test: // LEt's do it step by step to make it easier for others to see what's going on $img = __DIR__.'/applications/core/interface/giphy/logo.png'; // get the contents of the image $content = file_get_contents( $img); // encode it $content = base64_encode( $content); var_dump( \IPS\Http\Url::external( $communityUrl . "api/index.php?gallery/images" )->request()->login( $key, "" )->post( array( 'category' => 1, 'author' => 1, 'caption' => '<p>Testing API</p>', 'filename' => "my_img.png", 'image' => $content ) )->decodeJson() ); You could upload it to your community root directory after adjusting the URL,API Key and category variable to test it on your installation.
Marc Posted March 14, 2023 Posted March 14, 2023 Not tested, but try changing string A = @"data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(FileDir)).TrimEnd('=').Replace('+', '-').Replace('/', '_');//Convert.ToBase64String(imageArray);//; and replacing it with StreamReader sr = new StreamReader(FileDir); string A = sr.ReadToEnd(); sr.Close();
Schaken Posted March 14, 2023 Author Posted March 14, 2023 10 hours ago, Daniel F said: Yes, it's working. Here's my php version of a quick test: // LEt's do it step by step to make it easier for others to see what's going on $img = __DIR__.'/applications/core/interface/giphy/logo.png'; // get the contents of the image $content = file_get_contents( $img); // encode it $content = base64_encode( $content); var_dump( \IPS\Http\Url::external( $communityUrl . "api/index.php?gallery/images" )->request()->login( $key, "" )->post( array( 'category' => 1, 'author' => 1, 'caption' => '<p>Testing API</p>', 'filename' => "my_img.png", 'image' => $content ) )->decodeJson() ); You could upload it to your community root directory after adjusting the URL,API Key and category variable to test it on your installation. Thank you for double checking. now I can focus without doubt its on my end. sometimes I just have to verify all my possibilities and mark them all off 1 by 1 so i can find the exact problem, and work on that. I know C# isn't exactly what this community uses, but its where I am at and we all have to learn and start somewhere. this is my journey and I appreciate you all giving me a hand. I WILL master this, and I will post my work so anyone who may also have the issue, will find the answer.
Schaken Posted March 14, 2023 Author Posted March 14, 2023 6 hours ago, Marc Stridgen said: Not tested, but try changing string A = @"data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(FileDir)).TrimEnd('=').Replace('+', '-').Replace('/', '_');//Convert.ToBase64String(imageArray);//; and replacing it with StreamReader sr = new StreamReader(FileDir); string A = sr.ReadToEnd(); sr.Close(); Nice idea, but this gave me a "No_Image" and I have got this alot lately with my attempts last night. Seems "No_Image" is returned when the image is not readable, which tells me I'm breaking the image down wrong. Since the API says it needs to be "Encoded Base64" I just assume I need to use Convert.ToBase64String() but I think my issue is before this, or maybe a part of this. When entering text I often find myself having to use System.Text.RegularExpressions.Regex.Unescape() to make it URL friendly. I believe there must be some combo that I need to do here between them but I can't seem to crack it.
Schaken Posted March 14, 2023 Author Posted March 14, 2023 7 hours ago, Marc Stridgen said: Not tested, but try changing string A = @"data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(FileDir)).TrimEnd('=').Replace('+', '-').Replace('/', '_');//Convert.ToBase64String(imageArray);//; and replacing it with StreamReader sr = new StreamReader(FileDir); string A = sr.ReadToEnd(); sr.Close(); I believe this would actually work great for the downloads app. For everything else it just wants the raw file I believe, but for some reason the gallery app wants images in 64 base.
Schaken Posted March 15, 2023 Author Posted March 15, 2023 19 hours ago, Daniel F said: Yes, it's working. Here's my php version of a quick test: // LEt's do it step by step to make it easier for others to see what's going on $img = __DIR__.'/applications/core/interface/giphy/logo.png'; // get the contents of the image $content = file_get_contents( $img); // encode it $content = base64_encode( $content); var_dump( \IPS\Http\Url::external( $communityUrl . "api/index.php?gallery/images" )->request()->login( $key, "" )->post( array( 'category' => 1, 'author' => 1, 'caption' => '<p>Testing API</p>', 'filename' => "my_img.png", 'image' => $content ) )->decodeJson() ); You could upload it to your community root directory after adjusting the URL,API Key and category variable to test it on your installation. Doing some google search.. $content = file_get_contents( $img); // encode it $content = base64_encode( $content); this part you entered, is the same as this in C#: StreamReader sr = new StreamReader(filePath); string sContentsa = sr.ReadToEnd(); sr.Close(); and public static string EncodeTo64(string toEncode) { byte[] toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode); return Convert.ToBase64String(toEncodeAsBytes); } So I tried this.. StreamReader sr = new StreamReader(filePath); string sContentsa = sr.ReadToEnd(); sr.Close(); Dictionary<string, string> content = new Dictionary<string, string>(); content.Add("category", "27"); content.Add("image", EncodeTo64(sContentsa)); content.Add("caption", ImageTitle.text); content.Add("filename", ImageTitle.text); content.Add("description", ImageDescription.text); using (UnityWebRequest www = UnityWebRequest.Post("https://XXXXXXXXXXX.com/api/gallery/images", content)) { www.SetRequestHeader("Authorization", "Bearer " + OAH.BearerID); yield return www.SendWebRequest(); if (www.result == UnityWebRequest.Result.ConnectionError) { Debug.Log("Error While Sending TEST: " + www.error); } else { string result = www.downloadHandler.text; string FullTXT = System.Text.RegularExpressions.Regex.Unescape(result); Debug.Log("TEST: " + FullTXT); } } public static string EncodeTo64(string toEncode) { byte[] toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode); return Convert.ToBase64String(toEncodeAsBytes); } And goofy enough I still got the exact same result. Do you think there may be a setting that I have set wrong in my ACP? the only thing I get in my ACP is this: I am starting to think maybe the code is right, but maybe I have something in my ACP set to block it on accident.
Interferon Posted October 5 Posted October 5 I was able to get this working in C++. I think the only different in my code is I used the url_encode function to make the base64 data "nice". std::string url_encode(const std::string& decoded) { const auto encoded_value = curl_easy_escape(nullptr, decoded.c_str(), static_cast<int>(decoded.length())); std::string result(encoded_value); curl_free(encoded_value); return result; } bool UploadScreenshot(const WString& path, const WString& title, const WString& description) { auto buffer = LoadBuffer(path); auto s = base64_encode((const unsigned char*)buffer->Data(), buffer->GetSize()); std::string options = ("category=1&caption=MyDescription&title=" + StripAll(path).ToUtf8String() + "&author=1"); options += "&filename=" + path.ToUtf8String(); options += "&image=" + url_encode(s); auto j3 = InvisionPower::APIPost("/gallery/images/", accesstoken, options); if (j3["response"].is_string()) { Print(std::string(j3["response"])); } return true; }
Recommended Posts