From what I understand, dynamic typing is the same as weak typing and strong typing is the same as static typing, but I'm not sure I'm correct.
Static typing is when your type checking occurs at compile time. You must define a type for your variables inside of your code and any operations you perform on your data would be checked by the compiler.
Dynamic typing is when your type checking occurs at runtime. Instead of errors coming up when you compile your code you will get runtime errors if you try performing operations on incompatible types. However, you will get the benefit of having more versatile functions as they can be written once for multiple data types.
When you have strong typing, you will only be allowed operations on the data by direct manipulation of the objects of that data type.
Weak typing allows you to operate on data without considering its type. Some language do this through pointers. Other languages will convert one of your types to the other before performing the operations.
The links I included have a bit more detailed (and probably clearer) explanations.