Stichoza / google-translate-php

🔤 Free Google Translate API PHP Package. Translates totally free of charge.
MIT License
1.82k stars 384 forks source link

Error 403 Forbidden #32

Closed AngelSotomayor closed 8 years ago

AngelSotomayor commented 8 years ago

Till yesterday everything was working perfectly with your translator, but today I'm getting the next error: Fatal error: Uncaught exception 'ErrorException' with message 'Client error response [url] http://translate.google.com/translate_a/t [status code] 403 [reason phrase] Forbidden' And the stack trace says that comes from lines 215, 247 and 143 of the method TranslateClient.php. Do you suspect which is the problem?

AngelSotomayor commented 8 years ago

Finally, its working again, so I suppose that was an error from google maybe?

Stichoza commented 8 years ago

Yup, I guess it was Google's problem or maybe some network related. Here is a list of exceptions that you might get. You can wrap your code in a try-catch block to handle this kind of exceptions.

AngelSotomayor commented 8 years ago

Could it be that google has banned or restricted my ip?

josepamado commented 8 years ago

It is not working for me. I think they have changed the URL from http://translate.google.com/translate_a/t to https://translate.google.com/#[lang_from]/[lang_to]/[text_to_translate]

tehmaestro commented 8 years ago

It's not working for me either, and I've just tried this library. I guess something changed. I wasn't able to fix it yet, I've been playing with the query params.

Stichoza commented 8 years ago

I run tests several times and they fail randomly.

and so on. It's weird :unamused:

Stichoza commented 8 years ago

I'll push a dummy commit to see what will travis get. Update: Travis tests failed (in random manner, as mentioned above)

quanglam2807 commented 8 years ago

Google just updated the API to add a tk param, but it always changes so I think we need to figure out how to generate it.

https://translate.google.com/translate_a/single?client=t&sl=en&tl=it&hl=en&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=at&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&kc=1&tk=685310.807246&q=c

tk=685310.807246

laan commented 8 years ago

I get the same error. Is there some solutions?

tehmaestro commented 8 years ago

I confirm it is the tk parameter. This parameter depends on the string, and it seems it is case sensitive. Just to confirm, when translating the following, do you guys get the same tk value ?

English to French

gaozhitw commented 8 years ago

@tehmaestro I got the same value

dhrubo001 commented 8 years ago

Yes i am facing the same problm..its worked properly yesterday but from today morning...it's giving the same problem....wat's the issue

quanglam2807 commented 8 years ago

@tehmaestro I think it also depends on something else. Did you try to use different browsers?

tehmaestro commented 8 years ago

EDIT: Actually no, there are the same values, regardless of the browser or computer. It might depend on the browser version though or operating system, I think. EDIT2: I get same values on different browsers, versions, OSs

quanglam2807 commented 8 years ago

So what should we do now? Big trouble...

Stichoza commented 8 years ago

I might be wrong, but as I see the tk is generated on front-end using js. I hope we'll find something useful in that super obfuscated js files

Stichoza commented 8 years ago

I copied the url from network log and it works from any browser an even from HTTP request testers.

In addition to tk, there are multiple dt params added. Removing them causes the translation to fail. I have no clue what those dt's mean

tehmaestro commented 8 years ago

Here are my findings. The part which generates the tk parameter in javascript is the TL function here:

    var QL = function(a) {
        return function() {
            return a
        }
    }
      , RL = function(a, b) {
        for (var c = 0; c < b.length - 2; c += 3) {
            var d = b.charAt(c + 2)
              , d = d >= t ? d.charCodeAt(0) - 87 : Number(d)
              , d = b.charAt(c + 1) == Tb ? a >>> d : a << d;
            a = b.charAt(c) == Tb ? a + d & 4294967295 : a ^ d
        }
        return a
    }
      , SL = null 
      , TL = function(a) {
        var b;
        if (null  === SL) {
            var c = QL(String.fromCharCode(84));
            b = QL(String.fromCharCode(75));
            c = [c(), c()];
            c[1] = b();
            SL = Number(window[c.join(b())]) || 0
        }
        b = SL;
        var d = QL(String.fromCharCode(116))
          , c = QL(String.fromCharCode(107))
          , d = [d(), d()];
        d[1] = c();
        for (var c = cb + d.join(k) + 
        mf, d = [], e = 0, f = 0; f < a.length; f++) {
            var g = a.charCodeAt(f);
            128 > g ? d[e++] = g : (2048 > g ? d[e++] = g >> 6 | 192 : (55296 == (g & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (g = 65536 + ((g & 1023) << 10) + (a.charCodeAt(++f) & 1023),
            d[e++] = g >> 18 | 240,
            d[e++] = g >> 12 & 63 | 128) : d[e++] = g >> 12 | 224,
            d[e++] = g >> 6 & 63 | 128),
            d[e++] = g & 63 | 128)
        }
        a = b || 0;
        for (e = 0; e < d.length; e++)
            a += d[e],
            a = RL(a, Vb);
        a = RL(a, Ub);
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;
        return c + (a.toString() + dd + (a ^ b))
    }

So, some stuff I discovered. For return c + (a.toString() + dd + (a ^ b)):

   c is '&tk=' string
   dd is '.' string

That would leave a and b to be discovered. It seems that b = window['TKK'] which is always 402874 . Not sure if this changes, but I tested multiple text queries and b's value did not change.

And then there's a. As you can see, there's a line here a = b || 0; which essentially makes a's value b.

d in the code above is a an array with the charcode of each character in the input string.So, for Dog , d is an array with 3 elements, [68, 111, 103].

I think this is the important part:

for (e = 0; e < d.length; e++)
            a += d[e],
            a = RL(a, Vb);
        a = RL(a, Ub);
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;

So, for each number in d array, it adds it to a, which is actually b, and applies RL. Anyway, maybe somebody can take it further, I kinda stopped here, cause I don't fully understand the operations in RL.

Also, Vb is +-a^+6 operation and Ub is +-3^+b+-f . I know ...

limonte commented 8 years ago

same issue here.

quanglam2807 commented 8 years ago

@tehmaestro Nicely done! I have also tried the same thing but I was unable to find the value of the constant. It's really nice that you can do it! SL = Number(window[c.join(b())]) || 0 This line is also what we need to figure out. Can you share the window values as I'm unable to find them?

helen5106 commented 8 years ago

I have finished this issue.

http://www.liuxiatool.com/t.php?tk=L


function shr32($x, $bits)
{

    if($bits <= 0){
        return $x;
    }
    if($bits >= 32){
        return 0;
    }

    $bin = decbin($x);
    $l = strlen($bin);

    if($l > 32){
        $bin = substr($bin, $l - 32, 32);
    }elseif($l < 32){
        $bin = str_pad($bin, 32, '0', STR_PAD_LEFT);
    }

    return bindec(str_pad(substr($bin, 0, 32 - $bits), 32, '0', STR_PAD_LEFT));
}        

function charCodeAt($str, $index)
{
    $char = mb_substr($str, $index, 1, 'UTF-8');

    if (mb_check_encoding($char, 'UTF-8'))
    {
        $ret = mb_convert_encoding($char, 'UTF-32BE', 'UTF-8');
        return hexdec(bin2hex($ret));
    }
    else
    {
        return null;
    }
}

function RL($a, $b)
{
    for($c = 0; $c < strlen($b) - 2; $c +=3) {
        $d = $b{$c+2};
        $d = $d >= 'a' ? charCodeAt($d,0) - 87 : intval($d);
        $d = $b{$c+1} == '+' ? shr32($a, $d) : $a << $d;
        $a = $b{$c} == '+' ? ($a + $d & 4294967295) : $a ^ $d;
    }
    return $a;
}

function TL( $a )
{   
    $b = 402890;
    for ($d = array(), $e = 0, $f = 0; $f < strlen($a); $f++) {
        $g = charCodeAt($a, $f);

        if ( 128 > $g ) {
            $d[$e++] = $g; 
        } else {
            if ( 2048 > $g ) { 
                $d[$e++] = $g >> 6 | 192;
            } else { 
                if ( 55296 == ($g & 64512) && $f + 1 < strlen($a) && 56320 == (charCodeAt($a, $f + 1) & 64512) ) { 

                    $g = 65536 + (($g & 1023) << 10) + (charCodeAt($a, ++$f) & 1023);
                    $d[$e++] = $g >> 18 | 240; 
                    $d[$e++] = $g >> 12 & 63 | 128;
                } else {
                    $d[$e++] = $g >> 12 | 224;
                    $d[$e++] = $g >> 6 & 63 | 128;
                }
            }
            $d[$e++] = $g & 63 | 128;
        }
    }

    $a = $b;
    for ($e = 0; $e < count($d); $e++) {
        $a += $d[$e];
        $a = RL($a, '+-a^+6');
    }
    $a = RL($a, "+-3^+b+-f");
    if (0 > $a) $a = ($a & 2147483647) + 2147483648;
    $a %= pow(10, 6);
    return sprintf('%d.%d', $a, $a ^ $b);
}

$tk = (isset($_GET['tk']) && !empty($_GET['tk'])) ? $_GET['tk'] : 'love';
echo $tk . "=". TL($tk);
tehmaestro commented 8 years ago

Wow, congrats. I can confirm it works!

Stichoza commented 8 years ago

@helen5106 wow that's a great work :+1: But I still get 403 errors :( @tehmaestro How do you guys tested this token works?

quanglam2807 commented 8 years ago

@helen5106 Awesome! You save my life!

tehmaestro commented 8 years ago

I just added the functions written above in your class, and added the tk param to the request like so:

        $queryArray = array_merge($this->urlParams, [
            'text' => $data,
            'sl'   => $this->sourceLanguage,
            'tl'   => $this->targetLanguage,
            'tk' => $this->TL($data)
        ]);

Of course, this will not work when $data is an array, cause TL expects a string.

quanglam2807 commented 8 years ago

@tehmaestro It would be nice if someone can also figure out how to generate TL with an array. I really need it.

Stichoza commented 8 years ago

@tehmaestro Great! I'll make some preparation changes to the codebase. May I ask you to send me a pull request after I'm done with that changes?

laan commented 8 years ago

@helen5106 your code works to english. But if the text is UTF-8 chars, it will get the same error. Maybe need some decode. I will try to do this test.

tehmaestro commented 8 years ago

I've fixed the script so it works with UTF-8. I will be sending a pull request next week, just as an example.

kinni commented 8 years ago

It seems that the logic has been updated.

Translating from EN to FR Hello: 873579.750186 dog: 65510.448999 Dog: 78591.464126 cat: 795099.657370

Stichoza commented 8 years ago

@kinni Yeah I was afraid of that exact thing. There's no point fixing this if algorithm changes over short time.

tehmaestro commented 8 years ago

There are a couple of parameters that change, but that doesn't stop the translation from working. It still works. There are multiple tk values accepted for a string.

Saleh7 commented 8 years ago

change the chain in a short time :(

English -> Arabic
tk=376112.236340&q=cat
tk=846160.708436&q=Hello

Arabic -> English
tk=102845.505785&q=%D9%85%D8%B1%D8%AD%D8%A8%D8%A7
tk=750404.873792&q=%D9%82%D8%B7
quanglam2807 commented 8 years ago

@Stichoza Actually, even though they change it, they give a period of time for their apps to update. This happened a few months ago when they first added tk param: even though the requests on translate.google.com have proper tokens, I could use tk=0 to get through.

laan commented 8 years ago

@tehmaestro Would you please release the code for supporting UTF-8. Thanks very much.

johndag76 commented 8 years ago

I tested the code but it doesn't work at the moment... any update on this? The TL functions seems to generate wrong values with negative numbers

johndag76 commented 8 years ago

UPDATE: it works only with some words... only with some words/sentences it works. If there is an UTF character it doesn't work. We are really awaiting for the final working code :(

mouhsinelonly commented 8 years ago

this library doesn't work anymore :'(

johndag76 commented 8 years ago

At the moment it doesn't work anymore at least it's no more reliable... i've integrated the TL function and in some cases it works, weird enough it translates correctly in more cases on a live server than on my localhost. Main issues seems again about UTF8... translating from non accented characters works but translating from accented characters doesn't work.. hopefully for a quick and urgent pull request and a library update

tehmaestro commented 8 years ago

https://github.com/tehmaestro/google-translate-php/commit/9c5cc3bde5d9955d4c104c95c5dae8b52bc877a7

Saleh7 commented 8 years ago

@tehmaestro good job , thank you

Stichoza commented 8 years ago

I pushed two commits with simple (not working) token generator. You can send a PR with the new token generator class which implements TokenProviderInterface and then change it in the TranslateClient's defaultTokenProvider attribute (or simply pass the class name as a third parameter to constructor).

feokano commented 8 years ago

I noticed that it works from localmachine with "file_get_contents()", while the server only with Сurl.

johndag76 commented 8 years ago

Just tested the current class file https://github.com/tehmaestro/google-translate-php/commit/9c5cc3bde5d9955d4c104c95c5dae8b52bc877a7

I confirm that it works perfectly everywhere! both on localhost and remote server, for all languages and UTF8 characters. You are a genius!

helen5106 commented 8 years ago

sorry everyone, I made a mistake, and I have fixed this:

http://www.liuxiatool.com/t.php?tk=Espa%C3%B1ol

http://translate.google.cn/translate_a/single?client=t&sl=auto&tl=en&hl=zh-CN&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=at&ie=UTF-8&oe=UTF-8&otf=1&srcrom=1&ssel=3&tsel=3&kc=1&tk=190209.312011&q=Español


function TL( $a )
{   
    mb_internal_encoding("UTF-8");
    $b = 402890;
    for ($d = array(), $e = 0, $f = 0; $f < mb_strlen($a); $f++) {
        $g = charCodeAt($a, $f);

        if ( 128 > $g ) {
            $d[$e++] = $g; 
        } else {
            if ( 2048 > $g ) { 
                $d[$e++] = $g >> 6 | 192;
            } else { 
                if ( 55296 == ($g & 64512) && $f + 1 < mb_strlen($a) && 56320 == (charCodeAt($a, $f + 1) & 64512) ) { 

                    $g = 65536 + (($g & 1023) << 10) + (charCodeAt($a, ++$f) & 1023);
                    $d[$e++] = $g >> 18 | 240; 
                    $d[$e++] = $g >> 12 & 63 | 128;
                } else {
                    $d[$e++] = $g >> 12 | 224;
                    $d[$e++] = $g >> 6 & 63 | 128;
                }
            }
            $d[$e++] = $g & 63 | 128;
        }
    }

    $a = $b;
    for ($e = 0; $e < count($d); $e++) {
        $a += $d[$e];
        $a = RL($a, '+-a^+6');
    }
    $a = RL($a, "+-3^+b+-f");
    if (0 > $a) $a = ($a & 2147483647) + 2147483648;
    $a %= pow(10, 6);
    return sprintf('%d.%d', $a, $a ^ $b);
}
helen5106 commented 8 years ago

@tehmaestro You did it ,well done.You are Einstein in the world

dean1510 commented 8 years ago

Hello! Met a problem while porting this code to java Line if (0 > $a) $a = ($a & 2147483647) + 2147483648; in hex looks like if (0 > a) a = (a & 0x7FFFFFFF) + 0x80000000; and for 4-byte values naturally means (if result is negative - make it positive and then negative again). Indeed I get negative values in TK string.

johndag76 commented 8 years ago

Which was the mistake? There is an update version of the class that we should use with the updated code?

Stichoza commented 8 years ago

@tehmaestro, you're a genius for real :tada: Can you please do a small refactor to make something like SampleTokenGenerator for a pull request? You can name the new class TehMaestroTokenProvider :smile:

tehmaestro commented 8 years ago

So I've added a pull request. https://github.com/Stichoza/google-translate-php/pull/33 . Please note that most of the credits should go to @helen5106

Without his "translation" of the js code to PHP we would be nowhere. So big thanks!!. Please feel free to commit the changes in the pull request manually, on your own, if you want to do that. It's just an example.